diff --git a/esp8266/machine_pin.c b/esp8266/machine_pin.c
index d4c6d3dea765ad3c97379c2449dede019eb36ef7..1a263601b4a711727fd29f4c34cff0384858dc21 100644
--- a/esp8266/machine_pin.c
+++ b/esp8266/machine_pin.c
@@ -287,7 +287,7 @@ STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, mp_uint_t n_args, c
 }
 
 // constructor(id, ...)
-STATIC mp_obj_t pyb_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
 
     // get the wanted pin object
@@ -436,7 +436,7 @@ const mp_obj_type_t pyb_pin_type = {
     { &mp_type_type },
     .name = MP_QSTR_Pin,
     .print = pyb_pin_print,
-    .make_new = pyb_pin_make_new,
+    .make_new = mp_pin_make_new,
     .call = pyb_pin_call,
     .protocol = &pin_pin_p,
     .locals_dict = (mp_obj_t)&pyb_pin_locals_dict,
diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h
index b25bb8bb4515060bd8da8daf29cf8d67e1beb704..d0b4a7b4b93f93292a63a494e2002d85242c55dc 100644
--- a/esp8266/mpconfigport.h
+++ b/esp8266/mpconfigport.h
@@ -73,6 +73,7 @@
 #define MICROPY_PY_UZLIB            (1)
 #define MICROPY_PY_LWIP             (1)
 #define MICROPY_PY_MACHINE          (1)
+#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
 #define MICROPY_PY_MACHINE_PULSE    (1)
 #define MICROPY_PY_MACHINE_I2C      (1)
 #define MICROPY_PY_MACHINE_SPI      (1)
diff --git a/extmod/machine_signal.c b/extmod/machine_signal.c
index de6c3ff320accdb25eae5cbbec6821a205e5fd0d..b10d901662ebadabaa4a4b8b503ff2d2ab6794a0 100644
--- a/extmod/machine_signal.c
+++ b/extmod/machine_signal.c
@@ -27,6 +27,8 @@
 #include "py/mpconfig.h"
 #if MICROPY_PY_MACHINE
 
+#include <string.h>
+
 #include "py/obj.h"
 #include "py/runtime.h"
 #include "extmod/virtpin.h"
@@ -41,20 +43,73 @@ typedef struct _machine_signal_t {
 } machine_signal_t;
 
 STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
-    enum { ARG_pin, ARG_inverted };
-    static const mp_arg_t allowed_args[] = {
-        { MP_QSTR_, MP_ARG_OBJ | MP_ARG_REQUIRED },
-        { MP_QSTR_inverted, MP_ARG_BOOL, {.u_bool = false} },
-    };
+    mp_obj_t pin = args[0];
+    bool inverted = false;
+
+    #if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW)
+    mp_pin_p_t *pin_p = NULL;
+
+    if (MP_OBJ_IS_OBJ(pin)) {
+        mp_obj_base_t *pin_base = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
+        pin_p = (mp_pin_p_t*)pin_base->type->protocol;
+    }
+
+    if (pin_p == NULL) {
+        // If first argument isn't a Pin-like object, we filter out "inverted"
+        // from keyword arguments and pass them all to the exported Pin
+        // constructor to create one.
+        mp_obj_t pin_args[n_args + n_kw * 2];
+        memcpy(pin_args, args, n_args * sizeof(mp_obj_t));
+        const mp_obj_t *src = args + n_args;
+        mp_obj_t *dst = pin_args + n_args;
+        mp_obj_t *sig_value = NULL;
+        for (size_t cnt = n_kw; cnt; cnt--) {
+            if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_inverted)) {
+                inverted = mp_obj_is_true(src[1]);
+                n_kw--;
+            } else {
+                *dst++ = *src;
+                *dst++ = src[1];
+            }
+            if (*src == MP_OBJ_NEW_QSTR(MP_QSTR_value)) {
+                // Value is pertained to Signal, so we should invert
+                // it for Pin if needed, and we should do it only when
+                // inversion status is guaranteedly known.
+                sig_value = dst - 1;
+            }
+            src += 2;
+        }
 
-    mp_arg_val_t parsed_args[MP_ARRAY_SIZE(allowed_args)];
+        if (inverted && sig_value != NULL) {
+            *sig_value = mp_obj_is_true(*sig_value) ? MP_OBJ_NEW_SMALL_INT(0) : MP_OBJ_NEW_SMALL_INT(1);
+        }
 
-    mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, parsed_args);
+        // Here we pass NULL as a type, hoping that mp_pin_make_new()
+        // will just ignore it as set a concrete type. If not, we'd need
+        // to expose port's "default" pin type too.
+        pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args);
+    }
+    else
+    #endif
+    // Otherwise there should be 1 or 2 args
+    {
+        if (n_args == 1) {
+            if (n_kw == 0) {
+            } else if (n_kw == 1 && args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_inverted)) {
+                inverted = mp_obj_is_true(args[1]);
+            } else {
+                goto error;
+            }
+        } else {
+        error:
+            mp_raise_TypeError(NULL);
+        }
+    }
 
     machine_signal_t *o = m_new_obj(machine_signal_t);
     o->base.type = type;
-    o->pin = parsed_args[ARG_pin].u_obj;
-    o->inverted = parsed_args[ARG_inverted].u_bool;
+    o->pin = pin;
+    o->inverted = inverted;
     return MP_OBJ_FROM_PTR(o);
 }
 
diff --git a/extmod/virtpin.h b/extmod/virtpin.h
index 3821f9dec54ce2759dd7699387bca1d38c78b3c1..0410103505a9aa62afbe3b1d7ec5b3179232cdc5 100644
--- a/extmod/virtpin.h
+++ b/extmod/virtpin.h
@@ -38,3 +38,6 @@ typedef struct _mp_pin_p_t {
 
 int mp_virtual_pin_read(mp_obj_t pin);
 void mp_virtual_pin_write(mp_obj_t pin, int value);
+
+// If a port exposes a Pin object, it's constructor should be like this
+mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);