diff --git a/py/obj.h b/py/obj.h
index 7b4b0656f2f8ce94d9c35ca73cab0eae50abfb46..16c7c36dd174548d8c96e31922fcb39e77019824 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -144,6 +144,7 @@ mp_obj_t mp_obj_new_list(uint n, mp_obj_t *items);
 mp_obj_t mp_obj_new_list_reverse(uint n, mp_obj_t *items);
 mp_obj_t mp_obj_new_dict(int n_args);
 mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items);
+mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step);
 mp_obj_t mp_obj_new_bound_meth(mp_obj_t self, mp_obj_t meth);
 mp_obj_t mp_obj_new_class(struct _mp_map_t *class_locals);
 mp_obj_t mp_obj_new_instance(mp_obj_t clas);
@@ -214,6 +215,10 @@ mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
 // set
 void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item);
 
+// slice
+extern const mp_obj_type_t slice_type;
+void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step);
+
 // functions
 typedef struct _mp_obj_fun_native_t { // need this so we can define const objects (to go in ROM)
     mp_obj_base_t base;
diff --git a/py/objslice.c b/py/objslice.c
new file mode 100644
index 0000000000000000000000000000000000000000..619899b23232478c4aa7110cb58483d1eabd6e13
--- /dev/null
+++ b/py/objslice.c
@@ -0,0 +1,59 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+#include "nlr.h"
+#include "misc.h"
+#include "mpconfig.h"
+#include "obj.h"
+#include "runtime0.h"
+
+#if MICROPY_ENABLE_SLICE
+
+// TODO: This implements only variant of slice with 2 integer args only.
+// CPython supports 3rd arg (step), plus args can be arbitrary Python objects.
+typedef struct _mp_obj_slice_t {
+    mp_obj_base_t base;
+    machine_int_t start;
+    machine_int_t stop;
+} mp_obj_slice_t;
+
+void slice_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in) {
+    mp_obj_slice_t *o = o_in;
+    print(env, "slice(" INT_FMT ", " INT_FMT ")", o->start, o->stop);
+}
+
+const mp_obj_type_t slice_type = {
+    { &mp_const_type },
+    "slice",
+    slice_print,
+    NULL, // call_n
+    NULL, // unary_op
+    NULL, // binary_op
+    NULL, // getiter
+    NULL, // iternext
+    { { NULL, NULL }, }, // method list
+};
+
+// TODO: Make sure to handle "empty" values, which are signified by None in CPython
+mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) {
+    assert(ostep == NULL);
+    machine_int_t start = mp_obj_get_int(ostart);
+    machine_int_t stop = mp_obj_get_int(ostop);
+    mp_obj_slice_t *o = m_new(mp_obj_slice_t, 1);
+    o->base.type = &slice_type;
+    o->start = start;
+    o->stop = stop;
+    return (mp_obj_t)o;
+}
+
+void mp_obj_slice_get(mp_obj_t self_in, machine_int_t *start, machine_int_t *stop, machine_int_t *step) {
+    assert(MP_OBJ_IS_TYPE(self_in, &slice_type));
+    mp_obj_slice_t *self = self_in;
+    *start = self->start;
+    *stop = self->stop;
+    *step = 1;
+}
+
+#endif
diff --git a/stm/Makefile b/stm/Makefile
index d6c77e2bd7258b5f1317ca48998463c3b42ced8c..e84e21eae27585c0d04b4d841f4f212cbfd7514f 100644
--- a/stm/Makefile
+++ b/stm/Makefile
@@ -78,6 +78,7 @@ PY_O = \
 	objnone.o \
 	objrange.o \
 	objset.o \
+	objslice.o \
 	objstr.o \
 	objtuple.o \
 	objtype.o \
diff --git a/unix-cpy/Makefile b/unix-cpy/Makefile
index 48c31794600011cccbb833362fa36e2555b4fd59..7fee3438fbacfdd0267d0bfd3423cf145b88f5a0 100644
--- a/unix-cpy/Makefile
+++ b/unix-cpy/Makefile
@@ -43,6 +43,7 @@ PY_O = \
 	objnone.o \
 	objrange.o \
 	objset.o \
+	objslice.o \
 	objstr.o \
 	objtuple.o \
 	objtype.o \
diff --git a/unix/Makefile b/unix/Makefile
index fd5b6b43e0fc0928f7eb5be508e7fbaaa3fedcbb..38d6ba8e151633f5c3b9d94f25b8fb139079b875 100644
--- a/unix/Makefile
+++ b/unix/Makefile
@@ -50,6 +50,7 @@ PY_O = \
 	objnone.o \
 	objrange.o \
 	objset.o \
+	objslice.o \
 	objstr.o \
 	objtuple.o \
 	objtype.o \