diff --git a/IPython/consoleapp.py b/IPython/consoleapp.py
index bbcbce3..f04e05b 100644
--- a/IPython/consoleapp.py
+++ b/IPython/consoleapp.py
@@ -25,7 +25,8 @@ from IPython.utils.traitlets import (
     Dict, List, Unicode, CUnicode, CBool, Any
 )
 from IPython.kernel.zmq.session import Session
-from IPython.kernel.connect import ConnectionFileMixin
+from IPython.kernel import connect
+ConnectionFileMixin = connect.ConnectionFileMixin
 
 from IPython.utils.localinterfaces import localhost
 
diff --git a/IPython/kernel/__init__.py b/IPython/kernel/__init__.py
index 0cce18e..52f736e 100644
--- a/IPython/kernel/__init__.py
+++ b/IPython/kernel/__init__.py
@@ -1,67 +1,29 @@
-"""IPython kernels and associated utilities
-
-For connecting to kernels, use jupyter_client
 """
-
+Shim to maintain backwards compatibility with old IPython.kernel imports.
+"""
 # Copyright (c) IPython Development Team.
 # Distributed under the terms of the Modified BSD License.
 
-# Shim to maintain backwards compatibility with old IPython.kernel imports.
-
 import sys
 from warnings import warn
 
 warn("The `IPython.kernel` package has been deprecated. "
      "You should import from ipython_kernel or jupyter_client instead.")
 
-from IPython.utils.shimmodule import ShimModule
-
-# Shims for jupyter_client
-# Can't do a single shim, because the package didn't move all together
 
-for name in (
-    'adapter',
-    'blocking',
-    'channels',
-    'channelsabc',
-    'client',
-    'clientabc',
-    'connect',
-    'ioloop',
-    'kernelspec',
-    'kernelspecapp',
-    'launcher',
-    'manager',
-    'managerabc',
-    'multikernelmanager',
-    'restarter',
-    'threaded',
-    'tests.test_adapter',
-    'tests.test_connect',
-    'tests.test_kernelmanager',
-    'tests.test_kernelspec',
-    'tests.test_launcher',
-    'tests.test_multikernelmanager',
-    'tests.test_public_api',
-):
-    sys.modules['IPython.kernel.%s' % name] = \
-        ShimModule(name, mirror='jupyter_client.%s' % name)
+from IPython.utils.shimmodule import ShimModule
 
-# some files moved out of the zmq prefix
-for name in (
-    'session',
-    'tests.test_session',
-):
-    sys.modules['IPython.kernel.zmq.%s' % name] = \
-        ShimModule(name, mirror='jupyter_client.%s' % name)
-# preserve top-level API modules, all from jupyter_client
+# session moved relative to top-level
+sys.modules['IPython.kernel.zmq.session'] = ShimModule('session', mirror='jupyter_client.session')
 
-# just for friendlier zmq version check
-from . import zmq
+for pkg in ('comm', 'inprocess', 'resources', 'zmq'):
+    sys.modules['IPython.kernel.%s' % pkg] = ShimModule(pkg, mirror='ipython_kernel.%s' % pkg)
+for pkg in ('ioloop', 'blocking'):
+    sys.modules['IPython.kernel.%s' % pkg] = ShimModule(pkg, mirror='jupyter_client.%s' % pkg)
 
-from jupyter_client.connect import *
-from jupyter_client.launcher import *
-from jupyter_client.client import KernelClient
-from jupyter_client.manager import KernelManager, run_kernel
-from jupyter_client.blocking import BlockingKernelClient
-from jupyter_client.multikernelmanager import MultiKernelManager
+# required for `from IPython.kernel import PKG`
+from ipython_kernel import comm, inprocess, resources, zmq
+from jupyter_client import ioloop, blocking
+# public API
+from ipython_kernel.connect import *
+from jupyter_client import *
diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py
index 6b20cf2..3a679d0 100644
--- a/IPython/testing/iptest.py
+++ b/IPython/testing/iptest.py
@@ -172,6 +172,8 @@ class TestSection(object):
 
 shims = {
     'parallel': 'ipython_parallel',
+    'kernel': 'ipython_kernel',
+    'kernel.inprocess': 'ipython_kernel.inprocess',
 }
 
 # Name -> (include, exclude, dependencies_met)
diff --git a/ipython_kernel/launcher.py b/ipython_kernel/launcher.py
new file mode 100644
index 0000000..13492d3
--- /dev/null
+++ b/ipython_kernel/launcher.py
@@ -0,0 +1,226 @@
+"""Utilities for launching kernels
+"""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+import os
+import sys
+from subprocess import Popen, PIPE
+
+from IPython.utils.encoding import getdefaultencoding
+from IPython.utils.py3compat import cast_bytes_py2
+
+
+def swallow_argv(argv, aliases=None, flags=None):
+    """strip frontend-specific aliases and flags from an argument list
+
+    For use primarily in frontend apps that want to pass a subset of command-line
+    arguments through to a subprocess, where frontend-specific flags and aliases
+    should be removed from the list.
+
+    Parameters
+    ----------
+
+    argv : list(str)
+        The starting argv, to be filtered
+    aliases : container of aliases (dict, list, set, etc.)
+        The frontend-specific aliases to be removed
+    flags : container of flags (dict, list, set, etc.)
+        The frontend-specific flags to be removed
+
+    Returns
+    -------
+
+    argv : list(str)
+        The argv list, excluding flags and aliases that have been stripped
+    """
+
+    if aliases is None:
+        aliases = set()
+    if flags is None:
+        flags = set()
+
+    stripped = list(argv) # copy
+
+    swallow_next = False
+    was_flag = False
+    for a in argv:
+        if a == '--':
+            break
+        if swallow_next:
+            swallow_next = False
+            # last arg was an alias, remove the next one
+            # *unless* the last alias has a no-arg flag version, in which
+            # case, don't swallow the next arg if it's also a flag:
+            if not (was_flag and a.startswith('-')):
+                stripped.remove(a)
+                continue
+        if a.startswith('-'):
+            split = a.lstrip('-').split('=')
+            name = split[0]
+            # we use startswith because argparse accepts any arg to be specified
+            # by any leading section, as long as it is unique,
+            # so `--no-br` means `--no-browser` in the notebook, etc.
+            if any(alias.startswith(name) for alias in aliases):
+                stripped.remove(a)
+                if len(split) == 1:
+                    # alias passed with arg via space
+                    swallow_next = True
+                    # could have been a flag that matches an alias, e.g. `existing`
+                    # in which case, we might not swallow the next arg
+                    was_flag = name in flags
+            elif len(split) == 1 and any(flag.startswith(name) for flag in flags):
+                # strip flag, but don't swallow next, as flags don't take args
+                stripped.remove(a)
+
+    # return shortened list
+    return stripped
+
+
+def make_ipkernel_cmd(mod='ipython_kernel', executable=None, extra_arguments=[], **kw):
+    """Build Popen command list for launching an IPython kernel.
+
+    Parameters
+    ----------
+    mod : str, optional (default 'ipython_kernel')
+        A string of an IPython module whose __main__ starts an IPython kernel
+
+    executable : str, optional (default sys.executable)
+        The Python executable to use for the kernel process.
+
+    extra_arguments : list, optional
+        A list of extra arguments to pass when executing the launch code.
+
+    Returns
+    -------
+
+    A Popen command list
+    """
+    if executable is None:
+        executable = sys.executable
+    arguments = [ executable, '-m', mod, '-f', '{connection_file}' ]
+    arguments.extend(extra_arguments)
+
+    return arguments
+
+
+def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None,
+                        independent=False,
+                        cwd=None,
+                        **kw
+                        ):
+    """ Launches a localhost kernel, binding to the specified ports.
+
+    Parameters
+    ----------
+    cmd : Popen list,
+        A string of Python code that imports and executes a kernel entry point.
+
+    stdin, stdout, stderr : optional (default None)
+        Standards streams, as defined in subprocess.Popen.
+
+    independent : bool, optional (default False)
+        If set, the kernel process is guaranteed to survive if this process
+        dies. If not set, an effort is made to ensure that the kernel is killed
+        when this process dies. Note that in this case it is still good practice
+        to kill kernels manually before exiting.
+
+    cwd : path, optional
+        The working dir of the kernel process (default: cwd of this process).
+
+    Returns
+    -------
+
+    Popen instance for the kernel subprocess
+    """
+
+    # Popen will fail (sometimes with a deadlock) if stdin, stdout, and stderr
+    # are invalid. Unfortunately, there is in general no way to detect whether
+    # they are valid.  The following two blocks redirect them to (temporary)
+    # pipes in certain important cases.
+
+    # If this process has been backgrounded, our stdin is invalid. Since there
+    # is no compelling reason for the kernel to inherit our stdin anyway, we'll
+    # place this one safe and always redirect.
+    redirect_in = True
+    _stdin = PIPE if stdin is None else stdin
+
+    # If this process in running on pythonw, we know that stdin, stdout, and
+    # stderr are all invalid.
+    redirect_out = sys.executable.endswith('pythonw.exe')
+    if redirect_out:
+        blackhole = open(os.devnull, 'w')
+        _stdout = blackhole if stdout is None else stdout
+        _stderr = blackhole if stderr is None else stderr
+    else:
+        _stdout, _stderr = stdout, stderr
+
+    env = env if (env is not None) else os.environ.copy()
+
+    encoding = getdefaultencoding(prefer_stream=False)
+    kwargs = dict(
+        stdin=_stdin,
+        stdout=_stdout,
+        stderr=_stderr,
+        cwd=cwd,
+        env=env,
+    )
+
+    # Spawn a kernel.
+    if sys.platform == 'win32':
+        # Popen on Python 2 on Windows cannot handle unicode args or cwd
+        cmd = [ cast_bytes_py2(c, encoding) for c in cmd ]
+        if cwd:
+            cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii')
+            kwargs['cwd'] = cwd
+
+        from jupyter_client.parentpoller import ParentPollerWindows
+        # Create a Win32 event for interrupting the kernel
+        # and store it in an environment variable.
+        interrupt_event = ParentPollerWindows.create_interrupt_event()
+        env["JPY_INTERRUPT_EVENT"] = str(interrupt_event)
+        # deprecated old env name:
+        env["IPY_INTERRUPT_EVENT"] = env["JPY_INTERRUPT_EVENT"]
+
+        try:
+            from _winapi import DuplicateHandle, GetCurrentProcess, \
+                DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP
+        except:
+            from _subprocess import DuplicateHandle, GetCurrentProcess, \
+                DUPLICATE_SAME_ACCESS, CREATE_NEW_PROCESS_GROUP
+        # Launch the kernel process
+        if independent:
+            kwargs['creationflags'] = CREATE_NEW_PROCESS_GROUP
+        else:
+            pid = GetCurrentProcess()
+            handle = DuplicateHandle(pid, pid, pid, 0,
+                                     True, # Inheritable by new processes.
+                                     DUPLICATE_SAME_ACCESS)
+            env['JPY_PARENT_PID'] = str(int(handle))
+
+        proc = Popen(cmd, **kwargs)
+
+        # Attach the interrupt event to the Popen objet so it can be used later.
+        proc.win32_interrupt_event = interrupt_event
+
+    else:
+        if independent:
+            kwargs['preexec_fn'] = lambda: os.setsid()
+        else:
+            env['JPY_PARENT_PID'] = str(os.getpid())
+
+        proc = Popen(cmd, **kwargs)
+
+    # Clean up pipes created to work around Popen bug.
+    if redirect_in:
+        if stdin is None:
+            proc.stdin.close()
+
+    return proc
+
+__all__ = [
+    'swallow_argv',
+    'make_ipkernel_cmd',
+    'launch_kernel',
+]
diff --git a/jupyter_client/launcher.py b/jupyter_client/launcher.py
index e3c7cff..13492d3 100644
--- a/jupyter_client/launcher.py
+++ b/jupyter_client/launcher.py
@@ -78,12 +78,12 @@ def swallow_argv(argv, aliases=None, flags=None):
     return stripped
 
 
-def make_ipkernel_cmd(mod='IPython.kernel', executable=None, extra_arguments=[], **kw):
+def make_ipkernel_cmd(mod='ipython_kernel', executable=None, extra_arguments=[], **kw):
     """Build Popen command list for launching an IPython kernel.
 
     Parameters
     ----------
-    mod : str, optional (default 'IPython.kernel')
+    mod : str, optional (default 'ipython_kernel')
         A string of an IPython module whose __main__ starts an IPython kernel
 
     executable : str, optional (default sys.executable)