Index: kernel/generic/include/proc/program.h
===================================================================
--- kernel/generic/include/proc/program.h	(revision 4cac212c4712eb2b47dbe1538d4da0017288ff67)
+++ kernel/generic/include/proc/program.h	(revision bfd1546e49e40fb980d45ced0b409578ba8ab3ef)
@@ -60,6 +60,5 @@
 extern void program_ready(program_t *p);
 
-extern unative_t sys_program_spawn_loader(int *uspace_phone_id,
-    char *uspace_name, size_t name_len);
+extern unative_t sys_program_spawn_loader(char *uspace_name, size_t name_len);
 
 #endif
Index: kernel/generic/src/proc/program.c
===================================================================
--- kernel/generic/src/proc/program.c	(revision 4cac212c4712eb2b47dbe1538d4da0017288ff67)
+++ kernel/generic/src/proc/program.c	(revision bfd1546e49e40fb980d45ced0b409578ba8ab3ef)
@@ -191,8 +191,7 @@
 /** Syscall for creating a new loader instance from userspace.
  *
- * Creates a new task from the program loader image, connects a phone
- * to it and stores the phone id into the provided buffer.
- *
- * @param uspace_phone_id	Userspace address where to store the phone id.
+ * Creates a new task from the program loader image and sets
+ * the task name.
+ *
  * @param name			Name to set on the new task (typically the same
  *				as the command used to execute it).
@@ -200,20 +199,9 @@
  * @return 0 on success or an error code from @ref errno.h.
  */
-unative_t sys_program_spawn_loader(int *uspace_phone_id, char *uspace_name,
-    size_t name_len)
+unative_t sys_program_spawn_loader(char *uspace_name, size_t name_len)
 {
 	program_t p;
-	int fake_id;
 	int rc;
-	int phone_id;
 	char namebuf[TASK_NAME_BUFLEN];
-
-	fake_id = 0;
-
-	/* Before we even try creating the task, see if we can write the id */
-	rc = (unative_t) copy_to_uspace(uspace_phone_id, &fake_id,
-	    sizeof(fake_id));
-	if (rc != 0)
-		return rc;
 
 	/* Cap length of name and copy it from userspace. */
@@ -228,10 +216,4 @@
 	namebuf[name_len] = '\0';
 
-	/* Allocate the phone for communicating with the new task. */
-
-	phone_id = phone_alloc();
-	if (phone_id < 0)
-		return ELIMIT;
-
 	/* Spawn the new task. */
 
@@ -240,16 +222,4 @@
 		return rc;
 
-	phone_connect(phone_id, &p.task->answerbox);
-
-	/* No need to aquire lock before task_ready() */
-	rc = (unative_t) copy_to_uspace(uspace_phone_id, &phone_id,
-	    sizeof(phone_id));
-	if (rc != 0) {
-		/* Ooops */
-		ipc_phone_hangup(&TASK->phones[phone_id]);
-		task_kill(p.task->taskid);
-		return rc;
-	}
-
 	// FIXME: control the capabilities
 	cap_set(p.task, cap_get(TASK));
Index: uspace/lib/libc/generic/loader.c
===================================================================
--- uspace/lib/libc/generic/loader.c	(revision 4cac212c4712eb2b47dbe1538d4da0017288ff67)
+++ uspace/lib/libc/generic/loader.c	(revision bfd1546e49e40fb980d45ced0b409578ba8ab3ef)
@@ -35,4 +35,5 @@
 #include <ipc/ipc.h>
 #include <ipc/loader.h>
+#include <ipc/services.h>
 #include <libc.h>
 #include <task.h>
@@ -51,23 +52,17 @@
  *		de-allocated using free() after use).
  */
-loader_t *loader_spawn(const char *name)
-{
-	int phone_id, rc;
+int loader_spawn(const char *name)
+{
+	return __SYSCALL2(SYS_PROGRAM_SPAWN_LOADER,
+	    (sysarg_t) name, strlen(name));
+}
+
+loader_t *loader_connect(void)
+{
 	loader_t *ldr;
-
-	/*
-	 * Ask kernel to spawn a new loader task.
-	 */
-	rc = __SYSCALL3(SYS_PROGRAM_SPAWN_LOADER, (sysarg_t) &phone_id,
-		(sysarg_t) name, strlen(name));
-	if (rc != 0)
-		return NULL;
-
-	/*
-	 * Say hello so that the loader knows the incoming connection's
-	 * phone hash.
-	 */
-	rc = async_req_0_0(phone_id, LOADER_HELLO);
-	if (rc != EOK)
+	int phone_id;
+
+	phone_id = ipc_connect_me_to(PHONE_NS, SERVICE_LOAD, 0, 0);
+	if (phone_id < 0)
 		return NULL;
 
@@ -77,5 +72,5 @@
 
 	ldr->phone_id = phone_id;
-	return ldr;
+	return ldr;	
 }
 
Index: uspace/lib/libc/generic/task.c
===================================================================
--- uspace/lib/libc/generic/task.c	(revision 4cac212c4712eb2b47dbe1538d4da0017288ff67)
+++ uspace/lib/libc/generic/task.c	(revision bfd1546e49e40fb980d45ced0b409578ba8ab3ef)
@@ -64,6 +64,6 @@
 	int rc;
 
-	/* Spawn a program loader. */	
-	ldr = loader_spawn(path);
+	/* Connect to a program loader. */
+	ldr = loader_connect();
 	if (ldr == NULL)
 		return 0;
@@ -90,5 +90,4 @@
 
 	/* Run it. */
-	/* Load the program. */
 	rc = loader_run(ldr);
 	if (rc != EOK)
Index: uspace/lib/libc/include/ipc/services.h
===================================================================
--- uspace/lib/libc/include/ipc/services.h	(revision 4cac212c4712eb2b47dbe1538d4da0017288ff67)
+++ uspace/lib/libc/include/ipc/services.h	(revision bfd1546e49e40fb980d45ced0b409578ba8ab3ef)
@@ -39,5 +39,6 @@
 
 typedef enum {
-	SERVICE_PCI = 1,
+	SERVICE_LOAD = 1,
+	SERVICE_PCI,
 	SERVICE_KEYBOARD,
 	SERVICE_VIDEO,
Index: uspace/lib/libc/include/loader/loader.h
===================================================================
--- uspace/lib/libc/include/loader/loader.h	(revision 4cac212c4712eb2b47dbe1538d4da0017288ff67)
+++ uspace/lib/libc/include/loader/loader.h	(revision bfd1546e49e40fb980d45ced0b409578ba8ab3ef)
@@ -45,5 +45,6 @@
 } loader_t;
 
-extern loader_t *loader_spawn(const char *name);
+extern int loader_spawn(const char *);
+extern loader_t *loader_connect(void);
 extern int loader_get_task_id(loader_t *, task_id_t *);
 extern int loader_set_pathname(loader_t *, const char *);
Index: uspace/srv/loader/main.c
===================================================================
--- uspace/srv/loader/main.c	(revision 4cac212c4712eb2b47dbe1538d4da0017288ff67)
+++ uspace/srv/loader/main.c	(revision bfd1546e49e40fb980d45ced0b409578ba8ab3ef)
@@ -51,4 +51,5 @@
 #include <sys/types.h>
 #include <ipc/ipc.h>
+#include <ipc/services.h>
 #include <ipc/loader.h>
 #include <loader/pcb.h>
@@ -80,4 +81,6 @@
 static bool is_dyn_linked;
 
+/** Used to limit number of connections to one. */
+static bool connected;
 
 static void loader_get_taskid(ipc_callid_t rid, ipc_call_t *request)
@@ -297,4 +300,15 @@
 	ipc_call_t call;
 	int retval;
+
+	/* Already have a connection? */
+	if (connected) {
+		ipc_answer_0(iid, ELIMIT);
+		return;
+	}
+
+	connected = true;
+	
+	/* Accept the connection */
+	ipc_answer_0(iid, EOK);
 
 	/* Ignore parameters, the connection is already open */
@@ -339,29 +353,18 @@
 int main(int argc, char *argv[])
 {
-	ipc_callid_t callid;
-	ipc_call_t call;
-	ipcarg_t phone_hash;
-
-	/* The first call only communicates the incoming phone hash */
-	callid = ipc_wait_for_call(&call);
-
-	if (IPC_GET_METHOD(call) != LOADER_HELLO) {
-		if (IPC_GET_METHOD(call) != IPC_M_PHONE_HUNGUP)
-			ipc_answer_0(callid, EINVAL);
-		return 1;
-	}
-
-	ipc_answer_0(callid, EOK);
-	phone_hash = call.in_phone_hash;
-
-	/* 
-	 * Up until now async must not be used as it couldn't
-	 * handle incoming requests. (Which means e.g. printf() 
-	 * cannot be used)
-	 */
-	async_new_connection(phone_hash, 0, NULL, loader_connection);
+	ipcarg_t phonead;
+
+	connected = false;
+	
+	/* Set a handler of incomming connections. */
+	async_set_client_connection(loader_connection);
+
+	/* Register at naming service. */
+	if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0) 
+		return -1;
+	
 	async_manager();
 
-	/* not reached */
+	/* Never reached */
 	return 0;
 }
Index: uspace/srv/ns/ns.c
===================================================================
--- uspace/srv/ns/ns.c	(revision 4cac212c4712eb2b47dbe1538d4da0017288ff67)
+++ uspace/srv/ns/ns.c	(revision bfd1546e49e40fb980d45ced0b409578ba8ab3ef)
@@ -41,4 +41,5 @@
 #include <ipc/services.h>
 #include <stdio.h>
+#include <bool.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -48,4 +49,5 @@
 #include <libadt/hash_table.h>
 #include <sysinfo.h>
+#include <loader/loader.h>
 #include <ddi.h>
 #include <as.h>
@@ -57,4 +59,9 @@
 static int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call);
 static int connect_to_service(ipcarg_t service, ipc_call_t *call,
+    ipc_callid_t callid);
+
+void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call,
+    ipc_callid_t callid);
+void connect_to_clonable(ipcarg_t service, ipc_call_t *call,
     ipc_callid_t callid);
 
@@ -84,4 +91,21 @@
 static void *clockaddr = NULL;
 static void *klogaddr = NULL;
+
+/** Request for connection to a clonable service. */
+typedef struct {
+	link_t link;
+	ipcarg_t service;
+	ipc_call_t *call;
+	ipc_callid_t callid;
+} cs_req_t;
+
+/** List of clonable-service connection requests. */
+static link_t cs_req;
+
+/** Return true if @a service is clonable. */
+static bool service_clonable(int service)
+{
+	return service == SERVICE_LOAD;
+}
 
 static void get_as_area(ipc_callid_t callid, ipc_call_t *call, char *name,
@@ -117,4 +141,6 @@
 		return ENOMEM;
 	}
+
+	list_initialize(&cs_req);
 	
 	printf(NAME ": Accepting connections\n");
@@ -143,6 +169,12 @@
 			 * Server requests service registration.
 			 */
-			retval = register_service(IPC_GET_ARG1(call),
-			    IPC_GET_ARG5(call), &call);
+			if (service_clonable(IPC_GET_ARG1(call))) {
+				register_clonable(IPC_GET_ARG1(call),
+				    IPC_GET_ARG5(call), &call, callid);
+				continue;
+			} else {
+				retval = register_service(IPC_GET_ARG1(call),
+				    IPC_GET_ARG5(call), &call);
+			}
 			break;
 		case IPC_M_CONNECT_ME_TO:
@@ -150,6 +182,12 @@
 			 * Client requests to be connected to a service.
 			 */
-			retval = connect_to_service(IPC_GET_ARG1(call), &call,
-			    callid);
+			if (service_clonable(IPC_GET_ARG1(call))) {
+				connect_to_clonable(IPC_GET_ARG1(call),
+				    &call, callid);
+				continue;
+			} else {
+				retval = connect_to_service(IPC_GET_ARG1(call),
+				    &call, callid);
+			}
 			break;
 		default:
@@ -168,9 +206,9 @@
 /** Register service.
  *
- * @param service Service to be registered.
- * @param phone Phone to be used for connections to the service.
- * @param call Pointer to call structure.
- *
- * @return Zero on success or a value from @ref errno.h.
+ * @param service	Service to be registered.
+ * @param phone		Phone to be used for connections to the service.
+ * @param call		Pointer to call structure.
+ *
+ * @return		Zero on success or a value from @ref errno.h.
  */
 int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call)
@@ -182,5 +220,5 @@
 	};
 	hashed_service_t *hs;
-			
+
 	if (hash_table_find(&ns_hash_table, keys)) {
 		return EEXISTS;
@@ -203,7 +241,7 @@
 /** Connect client to service.
  *
- * @param service Service to be connected to.
- * @param call Pointer to call structure.
- * @param callid Call ID of the request.
+ * @param service	Service to be connected to.
+ * @param call		Pointer to call structure.
+ * @param callid	Call ID of the request.
  *
  * @return Zero on success or a value from @ref errno.h.
@@ -214,5 +252,5 @@
 	link_t *hlp;
 	hashed_service_t *hs;
-			
+
 	hlp = hash_table_find(&ns_hash_table, keys);
 	if (!hlp) {
@@ -222,4 +260,80 @@
 	return ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call), 
 		IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
+}
+
+/** Register clonable service.
+ *
+ * @param service	Service to be registered.
+ * @param phone		Phone to be used for connections to the service.
+ * @param call		Pointer to call structure.
+ */
+void register_clonable(ipcarg_t service, ipcarg_t phone, ipc_call_t *call,
+    ipc_callid_t callid)
+{
+	int rc;
+	cs_req_t *csr;
+
+	if (list_empty(&cs_req)) {
+		/* There was no pending connection request. */
+		printf(NAME ": Unexpected clonable server.\n");
+		ipc_answer_0(callid, EBUSY);
+		return;
+	}
+
+	csr = list_get_instance(cs_req.next, cs_req_t, link);
+	list_remove(&csr->link);
+
+	/* Currently we can only handle a single type of clonable service. */
+	assert(csr->service == SERVICE_LOAD);
+
+	ipc_answer_0(callid, EOK);
+
+	rc = ipc_forward_fast(csr->callid, phone, IPC_GET_ARG2(*csr->call),
+		IPC_GET_ARG3(*csr->call), 0, IPC_FF_NONE);
+
+	free(csr);
+}
+
+/** Connect client to clonable service.
+ *
+ * @param service	Service to be connected to.
+ * @param call		Pointer to call structure.
+ * @param callid	Call ID of the request.
+ *
+ * @return		Zero on success or a value from @ref errno.h.
+ */
+void connect_to_clonable(ipcarg_t service, ipc_call_t *call,
+    ipc_callid_t callid)
+{
+	int rc;
+	cs_req_t *csr;
+
+	assert(service == SERVICE_LOAD);
+
+	csr = malloc(sizeof(cs_req_t));
+	if (csr == NULL) {
+		ipc_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	/* Spawn a loader. */
+	rc = loader_spawn("loader");
+
+	if (rc < 0) {
+		free(csr);
+		ipc_answer_0(callid, rc);
+		return;
+	}
+
+	csr->service = service;
+	csr->call = call;
+	csr->callid = callid;
+
+	/*
+	 * We can forward the call only after the server we spawned connects
+	 * to us. Meanwhile we might need to service more connection requests.
+	 * Thus we store the call in a queue.
+	 */
+	list_append(&csr->link, &cs_req);
 }
 
