diff --git a/numpy/_distributor_init.py b/numpy/_distributor_init.py
index d893ba3..23e67aa 100644
--- a/numpy/_distributor_init.py
+++ b/numpy/_distributor_init.py
@@ -8,3 +8,29 @@ For example, this is a good place to put any checks for hardware requirements.
 The numpy standard source distribution will not put code in this file, so you
 can safely replace this file with your own version.
 """
+import sys
+
+class RTLD_for_MKL():
+    def __init__(self):
+        self.saved_rtld = None
+
+    def __enter__(self):
+        import ctypes
+        try:
+            self.saved_rtld = sys.getdlopenflags()
+            # python loads libraries with RTLD_LOCAL, but MKL requires RTLD_GLOBAL
+            # pre-load MKL with RTLD_GLOBAL before loading the native extension
+            sys.setdlopenflags(self.saved_rtld | ctypes.RTLD_GLOBAL)
+        except AttributeError:
+            pass
+        del ctypes
+
+    def __exit__(self, *args):
+        if self.saved_rtld:
+            sys.setdlopenflags(self.saved_rtld)
+            self.saved_rtld = None
+
+with RTLD_for_MKL():
+    from . import _mklinit
+
+del RTLD_for_MKL
diff --git a/numpy/_mklinitmodule.c b/numpy/_mklinitmodule.c
new file mode 100644
index 0000000..c3af525
--- /dev/null
+++ b/numpy/_mklinitmodule.c
@@ -0,0 +1,159 @@
+/* -*- c -*- */
+/*
+ Copyright (c) 2017, Intel Corporation
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+     * Redistributions of source code must retain the above copyright notice,
+       this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+     * Neither the name of Intel Corporation nor the names of its contributors
+       may be used to endorse or promote products derived from this software
+       without specific prior written permission.
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This is a dummy module whose purpose is to get distutils to generate the
+ * configuration files before the libraries are made.
+ */
+
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#define NO_IMPORT_ARRAY
+
+#if (defined(USING_MKL_RT) && defined(__linux__))
+#define FORCE_PRELOADING 1
+#define _GNU_SOURCE 1
+#include <dlfcn.h>
+#include <string.h>
+#undef _GNU_SOURCE
+#endif
+
+#include <Python.h>
+#include <npy_pycompat.h>
+#include "mkl.h"
+
+static struct PyMethodDef methods[] = {
+    {NULL, NULL, 0, NULL}
+};
+
+static inline void _set_mkl_ilp64() {
+#ifdef USING_MKL_RT
+    int i = mkl_set_interface_layer(MKL_INTERFACE_ILP64);
+#endif
+    return;
+}
+
+static inline void _set_mkl_lp64() {
+#ifdef USING_MKL_RT
+    int i = mkl_set_interface_layer(MKL_INTERFACE_LP64);
+#endif
+    return;
+}
+
+static void _preload_threading_layer() {
+#if FORCE_PRELOADING
+#define VERBOSE(...) if(verbose) printf("Numpy + Intel(R) MKL: " __VA_ARGS__)
+#define SET_MTLAYER(L) do {                                      \
+            VERBOSE("setting Intel(R) MKL to use " #L " OpenMP runtime\n");  \
+            mkl_set_threading_layer(MKL_THREADING_##L);          \
+            setenv("MKL_THREADING_LAYER", #L, 0);                \
+        } while(0)
+#define PRELOAD(lib) do {                                        \
+            VERBOSE("preloading %s runtime\n", lib);             \
+            dlopen(lib, RTLD_LAZY|RTLD_GLOBAL);                  \
+        } while(0)
+
+    const char *libiomp = "libiomp5.so";
+    const char *verbose = getenv("MKL_VERBOSE");
+    const char *mtlayer = getenv("MKL_THREADING_LAYER");
+    void *omp = dlsym(RTLD_DEFAULT, "omp_get_num_threads");
+    const char *omp_name = "(unidentified)";
+    const char *iomp = NULL; /* non-zero indicates Intel OpenMP is loaded */
+    Dl_info omp_info;
+
+    if(verbose && (verbose[0] == 0 || atoi(verbose) == 0))
+        verbose = NULL;
+
+    VERBOSE("THREADING LAYER: %s\n", mtlayer);
+
+    if(omp) {
+        if(dladdr(omp, &omp_info)) {
+            omp_name = basename(omp_info.dli_fname); /* GNU version doesn't modify argument */
+            iomp = strstr(omp_name, libiomp);
+        }
+        VERBOSE("%sOpenMP runtime %s is already loaded\n", iomp?"Intel(R) ":"", omp_name);
+    }
+    if(!mtlayer || mtlayer[0] == 0) {                /* unset or empty */
+        if(omp) {                                    /* if OpenMP runtime is loaded */
+            if(iomp)                                 /* if Intel runtime is loaded */
+                SET_MTLAYER(INTEL);
+            else                                     /* otherwise, assume it is GNU OpenMP */
+                SET_MTLAYER(GNU);
+        } else {                                     /* nothing is loaded */
+            SET_MTLAYER(INTEL);
+            PRELOAD(libiomp);
+        }
+    } else if(strcasecmp(mtlayer, "intel") == 0) {   /* Intel runtime is requested */
+        if(omp && !iomp) {
+            fprintf(stderr, "Error: Numpy + Intel(R) MKL: MKL_THREADING_LAYER=INTEL is incompatible with %s library."
+                            "\n\tTry to import numpy first or set the threading layer accordingly. "
+                            "Set NPY_MKL_FORCE_INTEL to force it.\n", omp_name);
+            if(!getenv("NPY_MKL_FORCE_INTEL"))
+                exit(1);
+        } else
+            PRELOAD(libiomp);
+    }
+#endif
+    return;
+}
+
+static inline void _set_mkl_interface() {
+    _set_mkl_lp64();
+    _preload_threading_layer();
+}
+
+#if defined(NPY_PY3K)
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    "mklinit",
+    NULL,
+    -1,
+    methods,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+#endif
+
+/* Initialization function for the module */
+#if defined(NPY_PY3K)
+PyMODINIT_FUNC PyInit__mklinit(void) {
+    PyObject *m;
+
+    _set_mkl_interface();
+    m = PyModule_Create(&moduledef);
+    if (!m) {
+        return NULL;
+    }
+
+    return m;
+}
+#else
+PyMODINIT_FUNC
+init_mklinit(void) {
+    _set_mkl_interface();
+    Py_InitModule("_mklinit", methods);
+}
+#endif
diff --git a/numpy/setup.py b/numpy/setup.py
index d794e92..0098b56 100644
--- a/numpy/setup.py
+++ b/numpy/setup.py
@@ -4,8 +4,19 @@ from __future__ import division, print_function
 
 def configuration(parent_package='',top_path=None):
     from numpy.distutils.misc_util import Configuration
-    config = Configuration('numpy', parent_package, top_path)
+    from numpy.distutils.system_info import get_info
+
+    defs = []
+    libs = get_info('mkl').get('libraries', [])
+    if any(['mkl_rt' in li for li in libs]):
+        #libs += ['dl'] - by default on Linux
+        defs += [('USING_MKL_RT', None)]
 
+    config = Configuration('numpy', parent_package, top_path)
+    config.add_extension('_mklinit',
+                          sources=['_mklinitmodule.c'],
+                          define_macros=defs,
+                          extra_info=get_info('mkl'))
     config.add_subpackage('compat')
     config.add_subpackage('core')
     config.add_subpackage('distutils')
