diff --git a/IPython/frontend/qt/console/frontend_widget.py b/IPython/frontend/qt/console/frontend_widget.py
index a3e4c21..16f75f6 100644
--- a/IPython/frontend/qt/console/frontend_widget.py
+++ b/IPython/frontend/qt/console/frontend_widget.py
@@ -216,7 +216,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
 
         See parent class :meth:`execute` docstring for full details.
         """
-        msg_id = self.kernel_client.shell_channel.execute(source, hidden)
+        msg_id = self.kernel_client.execute(source, hidden)
         self._request_info['execute'][msg_id] = self._ExecutionRequest(msg_id, 'user')
         self._hidden = hidden
         if not hidden:
@@ -358,7 +358,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
         # generate uuid, which would be used as an indication of whether or
         # not the unique request originated from here (can use msg id ?)
         local_uuid = str(uuid.uuid1())
-        msg_id = self.kernel_client.shell_channel.execute('',
+        msg_id = self.kernel_client.execute('',
             silent=True, user_expressions={ local_uuid:expr })
         self._callback_dict[local_uuid] = callback
         self._request_info['execute'][msg_id] = self._ExecutionRequest(msg_id, 'silent_exec_callback')
@@ -671,7 +671,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
 
         # Send the metadata request to the kernel
         name = '.'.join(context)
-        msg_id = self.kernel_client.shell_channel.object_info(name)
+        msg_id = self.kernel_client.object_info(name)
         pos = self._get_cursor().position()
         self._request_info['call_tip'] = self._CallTipRequest(msg_id, pos)
         return True
@@ -682,7 +682,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
         context = self._get_context()
         if context:
             # Send the completion request to the kernel
-            msg_id = self.kernel_client.shell_channel.complete(
+            msg_id = self.kernel_client.complete(
                 '.'.join(context),                       # text
                 self._get_input_buffer_cursor_line(),    # line
                 self._get_input_buffer_cursor_column(),  # cursor_pos
diff --git a/IPython/kernel/channels.py b/IPython/kernel/channels.py
index 64e165a..9d04795 100644
--- a/IPython/kernel/channels.py
+++ b/IPython/kernel/channels.py
@@ -81,6 +81,7 @@ class ZMQSocketChannel(Thread):
     stream = None
     _address = None
     _exiting = False
+    proxy_methods = []
 
     def __init__(self, context, session, address):
         """Create a channel.
@@ -175,6 +176,14 @@ class ShellChannel(ZMQSocketChannel):
     command_queue = None
     # flag for whether execute requests should be allowed to call raw_input:
     allow_stdin = True
+    proxy_methods = [
+        'execute',
+        'complete',
+        'object_info',
+        'history',
+        'kernel_info',
+        'shutdown',
+    ]
 
     def __init__(self, context, session, address):
         super(ShellChannel, self).__init__(context, session, address)
@@ -451,6 +460,7 @@ class StdInChannel(ZMQSocketChannel):
     """The stdin channel to handle raw_input requests that the kernel makes."""
 
     msg_queue = None
+    proxy_methods = ['input']
 
     def __init__(self, context, session, address):
         super(StdInChannel, self).__init__(context, session, address)
diff --git a/IPython/kernel/client.py b/IPython/kernel/client.py
index 51ed4a2..ead8e44 100644
--- a/IPython/kernel/client.py
+++ b/IPython/kernel/client.py
@@ -69,6 +69,34 @@ class KernelClient(LoggingConfigurable, ConnectionFileMixin):
     _stdin_channel = Any
     _hb_channel = Any
 
+    # def __init__(self, *args, **kwargs):
+    #     super(KernelClient, self).__init__(*args, **kwargs)
+    #     # setup channel proxy methods, e.g.
+    #     # Client.execute => shell_channel.execute
+    #     for channel in ['shell', 'iopub', 'stdin', 'hb']:
+    #         cls = getattr(self, '%s_channel_class' % channel)
+    #         for method in cls.proxy_methods:
+    #             setattr(self, method, self._proxy_method(channel, method))
+    #
+    #--------------------------------------------------------------------------
+    # Channel proxy methods
+    #--------------------------------------------------------------------------
+
+    def _get_msg(channel, *args, **kwargs):
+        return channel.get_msg(*args, **kwargs)
+
+    def get_shell_msg(self, *args, **kwargs):
+        """Get a message from the shell channel"""
+        return self.shell_channel.get_msg(*args, **kwargs)
+
+    def get_iopub_msg(self, *args, **kwargs):
+        """Get a message from the iopub channel"""
+        return self.iopub_channel.get_msg(*args, **kwargs)
+
+    def get_stdin_msg(self, *args, **kwargs):
+        """Get a message from the stdin channel"""
+        return self.stdin_channel.get_msg(*args, **kwargs)
+
     #--------------------------------------------------------------------------
     # Channel management methods
     #--------------------------------------------------------------------------
@@ -84,10 +112,16 @@ class KernelClient(LoggingConfigurable, ConnectionFileMixin):
         """
         if shell:
             self.shell_channel.start()
+            for method in self.shell_channel.proxy_methods:
+                setattr(self, method, getattr(self.shell_channel, method))
         if iopub:
             self.iopub_channel.start()
+            for method in self.iopub_channel.proxy_methods:
+                setattr(self, method, getattr(self.iopub_channel, method))
         if stdin:
             self.stdin_channel.start()
+            for method in self.stdin_channel.proxy_methods:
+                setattr(self, method, getattr(self.stdin_channel, method))
             self.shell_channel.allow_stdin = True
         else:
             self.shell_channel.allow_stdin = False
diff --git a/IPython/kernel/tests/test_message_spec.py b/IPython/kernel/tests/test_message_spec.py
index 42c5648..a8fc5c6 100644
--- a/IPython/kernel/tests/test_message_spec.py
+++ b/IPython/kernel/tests/test_message_spec.py
@@ -63,20 +63,15 @@ def flush_channels(kc=None):
 
 def execute(code='', kc=None, **kwargs):
     """wrapper for doing common steps for validating an execution request"""
-    if kc is None:
-        kc = KC
-    shell = kc.shell_channel
-    sub = kc.iopub_channel
-    
-    msg_id = shell.execute(code=code, **kwargs)
-    reply = shell.get_msg(timeout=2)
+    msg_id = KC.execute(code=code, **kwargs)
+    reply = KC.get_shell_msg(timeout=2)
     list(validate_message(reply, 'execute_reply', msg_id))
-    busy = sub.get_msg(timeout=2)
+    busy = KC.get_iopub_msg(timeout=2)
     list(validate_message(busy, 'status', msg_id))
     nt.assert_equal(busy['content']['execution_state'], 'busy')
     
     if not kwargs.get('silent'):
-        pyin = sub.get_msg(timeout=2)
+        pyin = KC.get_iopub_msg(timeout=2)
         list(validate_message(pyin, 'pyin', msg_id))
         nt.assert_equal(pyin['content']['code'], code)
     
@@ -302,9 +297,8 @@ def validate_message(msg, msg_type=None, parent=None):
 def test_execute():
     flush_channels()
     
-    shell = KC.shell_channel
-    msg_id = shell.execute(code='x=1')
-    reply = shell.get_msg(timeout=2)
+    msg_id = KC.execute(code='x=1')
+    reply = KC.get_shell_msg(timeout=2)
     for tst in validate_message(reply, 'execute_reply', msg_id):
         yield tst
 
@@ -383,10 +377,8 @@ def test_user_expressions():
 def test_oinfo():
     flush_channels()
 
-    shell = KC.shell_channel
-    
-    msg_id = shell.object_info('a')
-    reply = shell.get_msg(timeout=2)
+    msg_id = KC.object_info('a')
+    reply = KC.get_shell_msg(timeout=2)
     for tst in validate_message(reply, 'object_info_reply', msg_id):
         yield tst
 
@@ -395,12 +387,10 @@ def test_oinfo():
 def test_oinfo_found():
     flush_channels()
 
-    shell = KC.shell_channel
-    
     msg_id, reply = execute(code='a=5')
     
-    msg_id = shell.object_info('a')
-    reply = shell.get_msg(timeout=2)
+    msg_id = KC.object_info('a')
+    reply = KC.get_shell_msg(timeout=2)
     for tst in validate_message(reply, 'object_info_reply', msg_id):
         yield tst
     content = reply['content']
@@ -413,12 +403,10 @@ def test_oinfo_found():
 def test_oinfo_detail():
     flush_channels()
 
-    shell = KC.shell_channel
-    
     msg_id, reply = execute(code='ip=get_ipython()')
     
-    msg_id = shell.object_info('ip.object_inspect', detail_level=2)
-    reply = shell.get_msg(timeout=2)
+    msg_id = KC.object_info('ip.object_inspect', detail_level=2)
+    reply = KC.get_shell_msg(timeout=2)
     for tst in validate_message(reply, 'object_info_reply', msg_id):
         yield tst
     content = reply['content']
@@ -432,10 +420,8 @@ def test_oinfo_detail():
 def test_oinfo_not_found():
     flush_channels()
 
-    shell = KC.shell_channel
-    
-    msg_id = shell.object_info('dne')
-    reply = shell.get_msg(timeout=2)
+    msg_id = KC.object_info('dne')
+    reply = KC.get_shell_msg(timeout=2)
     for tst in validate_message(reply, 'object_info_reply', msg_id):
         yield tst
     content = reply['content']
@@ -446,12 +432,10 @@ def test_oinfo_not_found():
 def test_complete():
     flush_channels()
 
-    shell = KC.shell_channel
-    
     msg_id, reply = execute(code="alpha = albert = 5")
     
-    msg_id = shell.complete('al', 'al', 2)
-    reply = shell.get_msg(timeout=2)
+    msg_id = KC.complete('al', 'al', 2)
+    reply = KC.get_shell_msg(timeout=2)
     for tst in validate_message(reply, 'complete_reply', msg_id):
         yield tst
     matches = reply['content']['matches']
@@ -463,10 +447,8 @@ def test_complete():
 def test_kernel_info_request():
     flush_channels()
 
-    shell = KC.shell_channel
-
-    msg_id = shell.kernel_info()
-    reply = shell.get_msg(timeout=2)
+    msg_id = KC.kernel_info()
+    reply = KC.get_shell_msg(timeout=2)
     for tst in validate_message(reply, 'kernel_info_reply', msg_id):
         yield tst
 
diff --git a/IPython/kernel/zmq/tests/test_embed_kernel.py b/IPython/kernel/zmq/tests/test_embed_kernel.py
index 9b2b87e..da1dc61 100644
--- a/IPython/kernel/zmq/tests/test_embed_kernel.py
+++ b/IPython/kernel/zmq/tests/test_embed_kernel.py
@@ -106,22 +106,20 @@ def test_embed_kernel_basic():
     ])
     
     with setup_kernel(cmd) as client:
-        shell = client.shell_channel
-    
         # oinfo a (int)
-        msg_id = shell.object_info('a')
-        msg = shell.get_msg(block=True, timeout=2)
+        msg_id = client.object_info('a')
+        msg = client.get_shell_msg(block=True, timeout=2)
         content = msg['content']
         nt.assert_true(content['found'])
     
-        msg_id = shell.execute("c=a*2")
-        msg = shell.get_msg(block=True, timeout=2)
+        msg_id = client.execute("c=a*2")
+        msg = client.get_shell_msg(block=True, timeout=2)
         content = msg['content']
         nt.assert_equal(content['status'], u'ok')
 
         # oinfo c (should be 10)
-        msg_id = shell.object_info('c')
-        msg = shell.get_msg(block=True, timeout=2)
+        msg_id = client.object_info('c')
+        msg = client.get_shell_msg(block=True, timeout=2)
         content = msg['content']
         nt.assert_true(content['found'])
         nt.assert_equal(content['string_form'], u'10')
@@ -139,25 +137,23 @@ def test_embed_kernel_namespace():
     ])
     
     with setup_kernel(cmd) as client:
-        shell = client.shell_channel
-    
         # oinfo a (int)
-        msg_id = shell.object_info('a')
-        msg = shell.get_msg(block=True, timeout=2)
+        msg_id = client.object_info('a')
+        msg = client.get_shell_msg(block=True, timeout=2)
         content = msg['content']
         nt.assert_true(content['found'])
         nt.assert_equal(content['string_form'], u'5')
 
         # oinfo b (str)
-        msg_id = shell.object_info('b')
-        msg = shell.get_msg(block=True, timeout=2)
+        msg_id = client.object_info('b')
+        msg = client.get_shell_msg(block=True, timeout=2)
         content = msg['content']
         nt.assert_true(content['found'])
         nt.assert_equal(content['string_form'], u'hi there')
 
         # oinfo c (undefined)
-        msg_id = shell.object_info('c')
-        msg = shell.get_msg(block=True, timeout=2)
+        msg_id = client.object_info('c')
+        msg = client.get_shell_msg(block=True, timeout=2)
         content = msg['content']
         nt.assert_false(content['found'])
 
@@ -177,17 +173,16 @@ def test_embed_kernel_reentrant():
     ])
     
     with setup_kernel(cmd) as client:
-        shell = client.shell_channel
         for i in range(5):
-            msg_id = shell.object_info('count')
-            msg = shell.get_msg(block=True, timeout=2)
+            msg_id = client.object_info('count')
+            msg = client.get_shell_msg(block=True, timeout=2)
             content = msg['content']
             nt.assert_true(content['found'])
             nt.assert_equal(content['string_form'], unicode(i))
             
             # exit from embed_kernel
-            shell.execute("get_ipython().exit_now = True")
-            msg = shell.get_msg(block=True, timeout=2)
+            client.execute("get_ipython().exit_now = True")
+            msg = client.get_shell_msg(block=True, timeout=2)
             time.sleep(0.2)