diff --git a/drivers/qmimodem/qmi.c b/drivers/qmimodem/qmi.c
index ee51a7db2368..89e1f8f40381 100644
--- a/drivers/qmimodem/qmi.c
+++ b/drivers/qmimodem/qmi.c
@@ -34,6 +34,7 @@
 #include <string.h>
 
 #include <glib.h>
+#include <ell/ell.h>
 
 #include <ofono/log.h>
 
@@ -54,6 +55,10 @@ struct qmi_version {
 	const char *name;
 };
 
+struct qmi_device_ops {
+	void (*destroy)(struct qmi_device *device);
+};
+
 struct qmi_device {
 	int ref_count;
 	int fd;
@@ -80,10 +85,15 @@ struct qmi_device {
 	void *shutdown_user_data;
 	qmi_destroy_func_t shutdown_destroy;
 	guint shutdown_source;
+	const struct qmi_device_ops *ops;
 	bool shutting_down : 1;
 	bool destroyed : 1;
 };
 
+struct qmi_device_qmux {
+	struct qmi_device super;
+};
+
 struct qmi_service {
 	int ref_count;
 	struct qmi_device *device;
@@ -949,15 +959,11 @@ static void service_destroy(gpointer data)
 	service->device = NULL;
 }
 
-struct qmi_device *qmi_device_new(int fd)
+static int qmi_device_init(struct qmi_device *device, int fd,
+					const struct qmi_device_ops *ops)
 {
-	struct qmi_device *device;
 	long flags;
 
-	device = g_try_new0(struct qmi_device, 1);
-	if (!device)
-		return NULL;
-
 	__debug_device(device, "device %p new", device);
 
 	device->ref_count = 1;
@@ -966,16 +972,14 @@ struct qmi_device *qmi_device_new(int fd)
 	device->close_on_unref = false;
 
 	flags = fcntl(device->fd, F_GETFL, NULL);
-	if (flags < 0) {
-		g_free(device);
-		return NULL;
-	}
+	if (flags < 0)
+		return -EIO;
 
 	if (!(flags & O_NONBLOCK)) {
-		if (fcntl(device->fd, F_SETFL, flags | O_NONBLOCK) < 0) {
-			g_free(device);
-			return NULL;
-		}
+		int r = fcntl(device->fd, F_SETFL, flags | O_NONBLOCK);
+
+		if (r < 0)
+			return -errno;
 	}
 
 	device->io = g_io_channel_unix_new(device->fd);
@@ -1000,7 +1004,9 @@ struct qmi_device *qmi_device_new(int fd)
 	device->next_control_tid = 1;
 	device->next_service_tid = 256;
 
-	return device;
+	device->ops = ops;
+
+	return 0;
 }
 
 struct qmi_device *qmi_device_ref(struct qmi_device *device)
@@ -1055,7 +1061,7 @@ void qmi_device_unref(struct qmi_device *device)
 	if (device->shutting_down)
 		device->destroyed = true;
 	else
-		g_free(device);
+		device->ops->destroy(device);
 }
 
 void qmi_device_set_debug(struct qmi_device *device,
@@ -1646,6 +1652,38 @@ done:
 	return res;
 }
 
+static void qmi_device_qmux_destroy(struct qmi_device *device)
+{
+	struct qmi_device_qmux *qmux =
+		l_container_of(device, struct qmi_device_qmux, super);
+
+	l_free(qmux);
+}
+
+static const struct qmi_device_ops qmux_ops = {
+	.destroy = qmi_device_qmux_destroy,
+};
+
+struct qmi_device *qmi_device_new_qmux(const char *device)
+{
+	struct qmi_device_qmux *qmux;
+	int fd;
+
+	fd = open(device, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+	if (fd < 0)
+		return NULL;
+
+	qmux = l_new(struct qmi_device_qmux, 1);
+
+	if (qmi_device_init(&qmux->super, fd, &qmux_ops) < 0) {
+		close(fd);
+		l_free(qmux);
+		return NULL;
+	}
+
+	return &qmux->super;
+}
+
 struct qmi_param *qmi_param_new(void)
 {
 	struct qmi_param *param;
diff --git a/drivers/qmimodem/qmi.h b/drivers/qmimodem/qmi.h
index fc2a309578c4..410ada04d8d7 100644
--- a/drivers/qmimodem/qmi.h
+++ b/drivers/qmimodem/qmi.h
@@ -81,8 +81,6 @@ typedef void (*qmi_debug_func_t)(const char *str, void *user_data);
 typedef void (*qmi_shutdown_func_t)(void *user_data);
 typedef void (*qmi_discover_func_t)(void *user_data);
 
-struct qmi_device *qmi_device_new(int fd);
-
 struct qmi_device *qmi_device_ref(struct qmi_device *device);
 void qmi_device_unref(struct qmi_device *device);
 
@@ -105,6 +103,8 @@ enum qmi_device_expected_data_format qmi_device_get_expected_data_format(
 bool qmi_device_set_expected_data_format(struct qmi_device *device,
 			enum qmi_device_expected_data_format format);
 
+struct qmi_device *qmi_device_new_qmux(const char *device);
+
 struct qmi_param;
 
 struct qmi_param *qmi_param_new(void);
diff --git a/plugins/gobi.c b/plugins/gobi.c
index 020d6ba2685e..07994666ded5 100644
--- a/plugins/gobi.c
+++ b/plugins/gobi.c
@@ -423,7 +423,6 @@ static int gobi_enable(struct ofono_modem *modem)
 {
 	struct gobi_data *data = ofono_modem_get_data(modem);
 	const char *device;
-	int fd;
 
 	DBG("%p", modem);
 
@@ -431,15 +430,7 @@ static int gobi_enable(struct ofono_modem *modem)
 	if (!device)
 		return -EINVAL;
 
-	fd = open(device, O_RDWR | O_NONBLOCK | O_CLOEXEC);
-	if (fd < 0)
-		return -EIO;
-
-	data->device = qmi_device_new(fd);
-	if (!data->device) {
-		close(fd);
-		return -ENOMEM;
-	}
+	data->device = qmi_device_new_qmux(device);
 
 	if (getenv("OFONO_QMI_DEBUG"))
 		qmi_device_set_debug(data->device, gobi_debug, "QMI: ");
