diff --git a/stmhal/can.c b/stmhal/can.c
index 6d582d44f38ab8a8f5f090db9aff04e61a005fbf..262c487f62e49400d39dc98bb20fcd32e3b9ad7d 100644
--- a/stmhal/can.c
+++ b/stmhal/can.c
@@ -27,12 +27,12 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
-#include <errno.h>
 
 #include "py/nlr.h"
 #include "py/objtuple.h"
 #include "py/runtime.h"
 #include "py/gc.h"
+#include "py/mperrno.h"
 #include "py/mphal.h"
 #include "bufhelper.h"
 #include "can.h"
@@ -817,7 +817,7 @@ mp_uint_t can_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *err
             ret |= MP_IOCTL_POLL_WR;
         }
     } else {
-        *errcode = EINVAL;
+        *errcode = MP_EINVAL;
         ret = -1;
     }
     return ret;
diff --git a/stmhal/modnetwork.c b/stmhal/modnetwork.c
index 86bf7379bbe5afde0a0cb2f08566145464d0ef1e..4425461a07c6bac0d86e6b56dfe0838236f20b46 100644
--- a/stmhal/modnetwork.c
+++ b/stmhal/modnetwork.c
@@ -27,7 +27,6 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
-#include <errno.h>
 
 #include "py/nlr.h"
 #include "py/objlist.h"
diff --git a/stmhal/modnwcc3k.c b/stmhal/modnwcc3k.c
index 85dc0585a808dd3d65432262b309b1bbeabb32e6..67be279428d31470e78d7ab809d3dd02abde71e7 100644
--- a/stmhal/modnwcc3k.c
+++ b/stmhal/modnwcc3k.c
@@ -26,7 +26,6 @@
 
 #include <string.h>
 #include <stdarg.h>
-#include <errno.h>
 
 // CC3000 defines its own ENOBUFS (different to standard one!)
 #undef ENOBUFS
diff --git a/stmhal/modnwwiznet5k.c b/stmhal/modnwwiznet5k.c
index b6f18354b9b4b9e9c1c4f754554b38a1d59e73c5..1dc05da59ec2b28f2d05d9a8044b20f14537f5b7 100644
--- a/stmhal/modnwwiznet5k.c
+++ b/stmhal/modnwwiznet5k.c
@@ -27,7 +27,6 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
-#include <errno.h>
 
 #include "py/nlr.h"
 #include "py/objlist.h"
diff --git a/stmhal/moduselect.c b/stmhal/moduselect.c
index 8923b4d50579eaf2059b44ba39a2148d1f22ebd5..e87478ae625e259b719a702074e0b8c6939fcd40 100644
--- a/stmhal/moduselect.c
+++ b/stmhal/moduselect.c
@@ -25,11 +25,11 @@
  */
 
 #include <stdio.h>
-#include <errno.h>
 
 #include "py/nlr.h"
 #include "py/obj.h"
 #include "py/objlist.h"
+#include "py/mperrno.h"
 #include "py/mphal.h"
 #include "pybioctl.h"
 
@@ -212,7 +212,7 @@ STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmas
     mp_obj_poll_t *self = self_in;
     mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
     if (elem == NULL) {
-        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOENT)));
+        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOENT)));
     }
     ((poll_obj_t*)elem->value)->flags = mp_obj_get_int(eventmask_in);
     return mp_const_none;
diff --git a/stmhal/modusocket.c b/stmhal/modusocket.c
index 8da56fa8bb181a6077f2ae287cfd4c22f514a4c2..9cc1f3314aa83024511718d4f3b3eedc3b0be8d6 100644
--- a/stmhal/modusocket.c
+++ b/stmhal/modusocket.c
@@ -26,12 +26,12 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <errno.h>
 
 #include "py/nlr.h"
 #include "py/objtuple.h"
 #include "py/objlist.h"
 #include "py/runtime.h"
+#include "py/mperrno.h"
 #include "netutils.h"
 #include "modnetwork.h"
 
@@ -116,7 +116,7 @@ STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog) {
     if (self->nic == MP_OBJ_NULL) {
         // not connected
         // TODO I think we can listen even if not bound...
-        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN)));
+        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOTCONN)));
     }
 
     int _errno;
@@ -186,7 +186,7 @@ STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
     mod_network_socket_obj_t *self = self_in;
     if (self->nic == MP_OBJ_NULL) {
         // not connected
-        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EPIPE)));
+        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EPIPE)));
     }
     mp_buffer_info_t bufinfo;
     mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
@@ -204,7 +204,7 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
     mod_network_socket_obj_t *self = self_in;
     if (self->nic == MP_OBJ_NULL) {
         // not connected
-        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN)));
+        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOTCONN)));
     }
     mp_int_t len = mp_obj_get_int(len_in);
     vstr_t vstr;
@@ -253,7 +253,7 @@ STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
     mod_network_socket_obj_t *self = self_in;
     if (self->nic == MP_OBJ_NULL) {
         // not connected
-        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN)));
+        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOTCONN)));
     }
     vstr_t vstr;
     vstr_init_len(&vstr, mp_obj_get_int(len_in));
@@ -314,7 +314,7 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
     mod_network_socket_obj_t *self = self_in;
     if (self->nic == MP_OBJ_NULL) {
         // not connected
-        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN)));
+        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOTCONN)));
     }
     mp_uint_t timeout;
     if (timeout_in == mp_const_none) {
diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h
index 6ec92acbfe2662bd3150941161d77e643cea4642..29e4bd8d87137279b4597eb45faa0decb2dcbdd9 100644
--- a/stmhal/mpconfigport.h
+++ b/stmhal/mpconfigport.h
@@ -61,6 +61,7 @@
 #define MICROPY_STREAMS_NON_BLOCK   (1)
 #define MICROPY_MODULE_WEAK_LINKS   (1)
 #define MICROPY_CAN_OVERRIDE_BUILTINS (1)
+#define MICROPY_USE_INTERNAL_ERRNO  (1)
 #define MICROPY_PY_FUNCTION_ATTRS   (1)
 #define MICROPY_PY_BUILTINS_STR_UNICODE (1)
 #define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
@@ -80,6 +81,7 @@
 #define MICROPY_PY_CMATH            (1)
 #define MICROPY_PY_IO               (1)
 #define MICROPY_PY_IO_FILEIO        (1)
+#define MICROPY_PY_UERRNO           (1)
 #define MICROPY_PY_UBINASCII        (1)
 #define MICROPY_PY_URANDOM          (1)
 #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
@@ -141,6 +143,7 @@ extern const struct _mp_obj_module_t mp_module_network;
     { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \
     { MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \
     { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \
+    { MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \
 
 // extra constants
 #define MICROPY_PORT_CONSTANTS \
diff --git a/stmhal/mphalport.c b/stmhal/mphalport.c
index 7a86989ffd810518c004d1ec09c2dde7a8e0541c..cea036921334c09c5d0e797f1d6013fbe6347585 100644
--- a/stmhal/mphalport.c
+++ b/stmhal/mphalport.c
@@ -1,7 +1,7 @@
-#include <errno.h>
 #include <string.h>
 
 #include "py/mpstate.h"
+#include "py/mperrno.h"
 #include "py/mphal.h"
 #include "usb.h"
 #include "uart.h"
@@ -9,9 +9,9 @@
 // this table converts from HAL_StatusTypeDef to POSIX errno
 const byte mp_hal_status_to_errno_table[4] = {
     [HAL_OK] = 0,
-    [HAL_ERROR] = EIO,
-    [HAL_BUSY] = EBUSY,
-    [HAL_TIMEOUT] = ETIMEDOUT,
+    [HAL_ERROR] = MP_EIO,
+    [HAL_BUSY] = MP_EBUSY,
+    [HAL_TIMEOUT] = MP_ETIMEDOUT,
 };
 
 NORETURN void mp_hal_raise(HAL_StatusTypeDef status) {
diff --git a/stmhal/pybstdio.c b/stmhal/pybstdio.c
index 72c164b36df983a56f174ca25683c6578fb98b9c..352b7c10c23411d8b83eae1f4bb49dfd216f369d 100644
--- a/stmhal/pybstdio.c
+++ b/stmhal/pybstdio.c
@@ -26,10 +26,10 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <errno.h>
 
 #include "py/obj.h"
 #include "py/stream.h"
+#include "py/mperrno.h"
 #include "py/mphal.h"
 
 // TODO make stdin, stdout and stderr writable objects so they can
@@ -69,7 +69,7 @@ STATIC mp_uint_t stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *er
         }
         return size;
     } else {
-        *errcode = EPERM;
+        *errcode = MP_EPERM;
         return MP_STREAM_ERROR;
     }
 }
@@ -80,7 +80,7 @@ STATIC mp_uint_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size,
         mp_hal_stdout_tx_strn_cooked(buf, size);
         return size;
     } else {
-        *errcode = EPERM;
+        *errcode = MP_EPERM;
         return MP_STREAM_ERROR;
     }
 }
diff --git a/stmhal/uart.c b/stmhal/uart.c
index 108236ca1aa8c522b72876de8b7f932d93eaaace..2b6f1e40d8e5b835323ee19db8b1ea43a7029f75 100644
--- a/stmhal/uart.c
+++ b/stmhal/uart.c
@@ -27,11 +27,11 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
-#include <errno.h>
 
 #include "py/nlr.h"
 #include "py/runtime.h"
 #include "py/stream.h"
+#include "py/mperrno.h"
 #include "py/mphal.h"
 #include "uart.h"
 #include "pybioctl.h"
@@ -829,7 +829,7 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i
 
     // check that size is a multiple of character width
     if (size & self->char_width) {
-        *errcode = EIO;
+        *errcode = MP_EIO;
         return MP_STREAM_ERROR;
     }
 
@@ -844,7 +844,7 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i
     // wait for first char to become available
     if (!uart_rx_wait(self, self->timeout)) {
         // return EAGAIN error to indicate non-blocking (then read() method returns None)
-        *errcode = EAGAIN;
+        *errcode = MP_EAGAIN;
         return MP_STREAM_ERROR;
     }
 
@@ -871,13 +871,13 @@ STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t
 
     // check that size is a multiple of character width
     if (size & self->char_width) {
-        *errcode = EIO;
+        *errcode = MP_EIO;
         return MP_STREAM_ERROR;
     }
 
     // wait to be able to write the first character. EAGAIN causes write to return None
     if (!uart_tx_wait(self, self->timeout)) {
-        *errcode = EAGAIN;
+        *errcode = MP_EAGAIN;
         return MP_STREAM_ERROR;
     }
 
@@ -917,7 +917,7 @@ STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t a
             ret |= MP_IOCTL_POLL_WR;
         }
     } else {
-        *errcode = EINVAL;
+        *errcode = MP_EINVAL;
         ret = MP_STREAM_ERROR;
     }
     return ret;
diff --git a/stmhal/usb.c b/stmhal/usb.c
index 1e1469c564a9482352a7132f2256ffb664afac46..b786fb758495223d6ee03fb8fdcb1f2e53caad64 100644
--- a/stmhal/usb.c
+++ b/stmhal/usb.c
@@ -26,7 +26,6 @@
 
 #include <stdarg.h>
 #include <string.h>
-#include <errno.h>
 
 #include "usbd_core.h"
 #include "usbd_desc.h"
@@ -37,6 +36,7 @@
 #include "py/objstr.h"
 #include "py/runtime.h"
 #include "py/stream.h"
+#include "py/mperrno.h"
 #include "bufhelper.h"
 #include "usb.h"
 #include "pybioctl.h"
@@ -483,7 +483,7 @@ STATIC mp_uint_t pyb_usb_vcp_read(mp_obj_t self_in, void *buf, mp_uint_t size, i
     int ret = USBD_CDC_Rx((byte*)buf, size, 0);
     if (ret == 0) {
         // return EAGAIN error to indicate non-blocking
-        *errcode = EAGAIN;
+        *errcode = MP_EAGAIN;
         return MP_STREAM_ERROR;
     }
     return ret;
@@ -493,7 +493,7 @@ STATIC mp_uint_t pyb_usb_vcp_write(mp_obj_t self_in, const void *buf, mp_uint_t
     int ret = USBD_CDC_Tx((const byte*)buf, size, 0);
     if (ret == 0) {
         // return EAGAIN error to indicate non-blocking
-        *errcode = EAGAIN;
+        *errcode = MP_EAGAIN;
         return MP_STREAM_ERROR;
     }
     return ret;
@@ -511,7 +511,7 @@ STATIC mp_uint_t pyb_usb_vcp_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_
             ret |= MP_IOCTL_POLL_WR;
         }
     } else {
-        *errcode = EINVAL;
+        *errcode = MP_EINVAL;
         ret = MP_STREAM_ERROR;
     }
     return ret;
@@ -600,7 +600,7 @@ STATIC mp_uint_t pyb_usb_hid_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_
             ret |= MP_IOCTL_POLL_WR;
         }
     } else {
-        *errcode = EINVAL;
+        *errcode = MP_EINVAL;
         ret = MP_STREAM_ERROR;
     }
     return ret;
diff --git a/tests/pyb/halerror.py.exp b/tests/pyb/halerror.py.exp
index 09c9f7ad92f092daa62416bf6b08b7c4cafaaaca..0f3f26253dc81adfb955ae60975e00b4f2213945 100644
--- a/tests/pyb/halerror.py.exp
+++ b/tests/pyb/halerror.py.exp
@@ -1,2 +1,2 @@
 OSError(5,)
-OSError(116,)
+OSError(110,)