diff --git a/system/ulib/fdio/private-remoteio.h b/system/ulib/fdio/private-remoteio.h
index fe6aafa74c229f3be512768aa02c7cb77100a842..202db4fca53b72ea1d7c74ddeac7cbb19cdc5eef 100644
--- a/system/ulib/fdio/private-remoteio.h
+++ b/system/ulib/fdio/private-remoteio.h
@@ -8,17 +8,7 @@
 
 #include "private.h"
 
-// Implements the |fdio_t| contract using |zxio_remote_t|.
-//
-// Has an ops table that translates fdio ops into zxio ops. Some of the fdio ops
-// require using the underlying handles in the |zxio_remote_t|, which is why
-// this object needs to use |zxio_remote_t| directly.
-//
-// Will be removed once the transition to the zxio backend is complete.
-typedef struct fdio_zxio_remote {
-    fdio_t io;
-    zxio_remote_t remote;
-} fdio_zxio_remote_t;
+zxio_remote_t* fdio_get_zxio_remote(fdio_t* io);
 
 // open operation directly on remoteio handle
 zx_status_t zxrio_open_handle(zx_handle_t h, const char* path, uint32_t flags,
diff --git a/system/ulib/fdio/service.c b/system/ulib/fdio/service.c
index abbde55b3378b64b178c0924e68a8ac562c89ee5..866d9af26e4719e846fccc17b8dc12e7754f8d5a 100644
--- a/system/ulib/fdio/service.c
+++ b/system/ulib/fdio/service.c
@@ -101,8 +101,8 @@ zx_status_t fdio_get_service_handle(int fd, zx_handle_t* out) {
             svc->h = ZX_HANDLE_INVALID;
             r = ZX_OK;
         } else if (io->ops == &fdio_zxio_remote_ops) {
-            fdio_zxio_remote_t* rio = (fdio_zxio_remote_t*) io;
-            r = zxio_release(&rio->remote.io, out);
+            zxio_remote_t* file = fdio_get_zxio_remote(io);
+            r = zxio_release(&file->io, out);
         } else {
             r = ZX_ERR_NOT_SUPPORTED;
             io->ops->close(io);
@@ -122,8 +122,8 @@ zx_handle_t fdio_unsafe_borrow_channel(fdio_t* io) {
         zxsvc_t* svc = (zxsvc_t*) io;
         return svc->h;
     } else if (io->ops == &fdio_zxio_remote_ops) {
-        fdio_zxio_remote_t* rio = (fdio_zxio_remote_t*) io;
-        return rio->remote.control;
+        zxio_remote_t* file = fdio_get_zxio_remote(io);
+        return file->control;
     }
     return ZX_HANDLE_INVALID;
 }
diff --git a/system/ulib/fdio/zxio.c b/system/ulib/fdio/zxio.c
index aa4caf56603f6d9bb2e6a32fa692c02397f99f1e..42612883a24cf8c7c0550828966095894bb9d670 100644
--- a/system/ulib/fdio/zxio.c
+++ b/system/ulib/fdio/zxio.c
@@ -21,19 +21,19 @@
 //
 // Every |fdio_t| implementation starts with an embedded |fdio_t|, which the
 // callers use to find the fdio |ops| table. There are several |fdio_t|
-// implementations that use zxio as a backed. All of them have an initial memory
-// layout that matches this structure. Defining this structure lets us define
+// implementations that use zxio as a backed. All of them have a memory layout
+// that matches this structure. Defining this structure lets us define
 // most of the fdio ops that use the zxio backend in a generic way.
 //
 // Will be removed once the transition to the zxio backend is complete.
 typedef struct fdio_zxio {
     fdio_t io;
-    zxio_t zio;
+    zxio_storage_t storage;
 } fdio_zxio_t;
 
 static inline zxio_t* fdio_get_zxio(fdio_t* io) {
     fdio_zxio_t* wrapper = (fdio_zxio_t*)io;
-    return &wrapper->zio;
+    return &wrapper->storage.io;
 }
 
 static zx_status_t fdio_zxio_close(fdio_t* io) {
@@ -201,18 +201,14 @@ static zx_status_t fdio_zxio_set_flags(fdio_t* io, uint32_t flags) {
 
 // Remote ----------------------------------------------------------------------
 
-static_assert(offsetof(fdio_zxio_t, zio) == offsetof(fdio_zxio_remote_t, remote.io),
-              "fdio_zxio_remote_t layout must match fdio_zxio_t");
-
 // POLL_MASK and POLL_SHIFT intend to convert the lower five POLL events into
 // ZX_USER_SIGNALs and vice-versa. Other events need to be manually converted to
 // a zx_signals_t, if they are desired.
 #define POLL_SHIFT  24
 #define POLL_MASK   0x1F
 
-static inline zxio_remote_t* fdio_get_zxio_remote(fdio_t* io) {
-    fdio_zxio_remote_t* wrapper = (fdio_zxio_remote_t*)io;
-    return &wrapper->remote;
+zxio_remote_t* fdio_get_zxio_remote(fdio_t* io) {
+    return (zxio_remote_t*)fdio_get_zxio(io);
 }
 
 static zx_status_t fdio_zxio_remote_open(fdio_t* io, const char* path,
@@ -428,7 +424,7 @@ fdio_ops_t fdio_zxio_remote_ops = {
 
 __EXPORT
 fdio_t* fdio_remote_create(zx_handle_t control, zx_handle_t event) {
-    fdio_zxio_remote_t* fv = fdio_alloc(sizeof(fdio_zxio_remote_t));
+    fdio_zxio_t* fv = fdio_alloc(sizeof(fdio_zxio_t));
     if (fv == NULL) {
         zx_handle_close(control);
         zx_handle_close(event);
@@ -437,7 +433,7 @@ fdio_t* fdio_remote_create(zx_handle_t control, zx_handle_t event) {
     fv->io.ops = &fdio_zxio_remote_ops;
     fv->io.magic = FDIO_MAGIC;
     atomic_init(&fv->io.refcount, 1);
-    zx_status_t status = zxio_remote_init(&fv->remote, control, event);
+    zx_status_t status = zxio_remote_init(&fv->storage, control, event);
     if (status != ZX_OK) {
         return NULL;
     }
@@ -446,21 +442,8 @@ fdio_t* fdio_remote_create(zx_handle_t control, zx_handle_t event) {
 
 // Vmofile ---------------------------------------------------------------------
 
-// Implements the |fdio_t| contract using |zxio_vmofile_t|.
-//
-// Has an ops table that translates fdio ops into zxio ops. Some of the fdio ops
-// require using the underlying handles in the |zxio_vmofile_t|, which is why
-// this object needs to use |zxio_vmofile_t| directly.
-//
-// Will be removed once the transition to the zxio backend is complete.
-typedef struct fdio_zxio_vmofile {
-    fdio_t io;
-    zxio_vmofile_t file;
-} fdio_zxio_vmofile_t;
-
 static inline zxio_vmofile_t* fdio_get_zxio_vmofile(fdio_t* io) {
-    fdio_zxio_vmofile_t* wrapper = (fdio_zxio_vmofile_t*)io;
-    return &wrapper->file;
+    return (zxio_vmofile_t*)fdio_get_zxio(io);
 }
 
 static zx_status_t fdio_zxio_vmofile_get_vmo(fdio_t* io, int flags,
@@ -535,7 +518,7 @@ fdio_ops_t fdio_zxio_vmofile_ops = {
 fdio_t* fdio_zxio_vmofile_create(zx_handle_t control, zx_handle_t vmo,
                                  zx_off_t offset, zx_off_t length,
                                  zx_off_t seek) {
-    fdio_zxio_vmofile_t* fv = fdio_alloc(sizeof(fdio_zxio_vmofile_t));
+    fdio_zxio_t* fv = fdio_alloc(sizeof(fdio_zxio_t));
     if (fv == NULL) {
         zx_handle_close(control);
         zx_handle_close(vmo);
@@ -544,7 +527,7 @@ fdio_t* fdio_zxio_vmofile_create(zx_handle_t control, zx_handle_t vmo,
     fv->io.ops = &fdio_zxio_vmofile_ops;
     fv->io.magic = FDIO_MAGIC;
     atomic_init(&fv->io.refcount, 1);
-    zx_status_t status = zxio_vmofile_init(&fv->file, control, vmo, offset,
+    zx_status_t status = zxio_vmofile_init(&fv->storage, control, vmo, offset,
                                            length, seek);
     if (status != ZX_OK) {
         return NULL;
@@ -554,21 +537,6 @@ fdio_t* fdio_zxio_vmofile_create(zx_handle_t control, zx_handle_t vmo,
 
 // Pipe ------------------------------------------------------------------------
 
-// Implements the |fdio_t| contract using |zxio_pipe_t|.
-//
-// Has an ops table that translates fdio ops into zxio ops. Some of the fdio ops
-// require using the underlying handles in the |zxio_pipe_t|, which is why
-// this object needs to use |zxio_pipe_t| directly.
-//
-// Will be removed once the transition to the zxio backend is complete.
-typedef struct fdio_zxio_pipe {
-    fdio_t io;
-    zxio_pipe_t pipe;
-} fdio_zxio_pipe_t;
-
-static_assert(offsetof(fdio_zxio_t, zio) == offsetof(fdio_zxio_pipe_t, pipe.io),
-              "fdio_zxio_pipe_t layout must match fdio_zxio_t");
-
 static zx_status_t read_blocking(zxio_t* io, void* buffer, size_t capacity,
                                  size_t* out_actual) {
     for (;;) {
@@ -624,8 +592,7 @@ static ssize_t write_internal(zxio_t* io, bool blocking, const void* data, size_
 }
 
 static inline zxio_pipe_t* fdio_get_zxio_pipe(fdio_t* io) {
-    fdio_zxio_pipe_t* wrapper = (fdio_zxio_pipe_t*)io;
-    return &wrapper->pipe;
+    return (zxio_pipe_t*)fdio_get_zxio(io);
 }
 
 static zx_status_t fdio_zxio_pipe_clone(fdio_t* io, zx_handle_t* handles, uint32_t* types) {
@@ -807,7 +774,7 @@ static fdio_ops_t fdio_zxio_pipe_ops = {
 };
 
 fdio_t* fdio_pipe_create(zx_handle_t socket) {
-    fdio_zxio_pipe_t* fv = fdio_alloc(sizeof(fdio_zxio_pipe_t));
+    fdio_zxio_t* fv = fdio_alloc(sizeof(fdio_zxio_t));
     if (fv == NULL) {
         zx_handle_close(socket);
         return NULL;
@@ -815,7 +782,7 @@ fdio_t* fdio_pipe_create(zx_handle_t socket) {
     fv->io.ops = &fdio_zxio_pipe_ops;
     fv->io.magic = FDIO_MAGIC;
     atomic_init(&fv->io.refcount, 1);
-    zx_status_t status = zxio_pipe_init(&fv->pipe, socket);
+    zx_status_t status = zxio_pipe_init(&fv->storage, socket);
     if (status != ZX_OK) {
         return NULL;
     }
diff --git a/system/ulib/zxio/include/lib/zxio/inception.h b/system/ulib/zxio/include/lib/zxio/inception.h
index eac4c188261a391544e9918fe90790af60ca2af2..6c461621517f13dcbf14744e6588959f884bedf5 100644
--- a/system/ulib/zxio/include/lib/zxio/inception.h
+++ b/system/ulib/zxio/include/lib/zxio/inception.h
@@ -35,7 +35,10 @@ typedef struct zxio_remote {
     zx_handle_t event;
 } zxio_remote_t;
 
-zx_status_t zxio_remote_init(zxio_remote_t* remote, zx_handle_t control,
+static_assert(sizeof(zxio_remote_t) <= sizeof(zxio_storage_t),
+              "zxio_remote_t must fit inside zxio_storage_t.");
+
+zx_status_t zxio_remote_init(zxio_storage_t* remote, zx_handle_t control,
                              zx_handle_t event);
 
 // vmofile ---------------------------------------------------------------------
@@ -51,7 +54,10 @@ typedef struct zxio_vmofile {
     mtx_t lock;
 } zxio_vmofile_t;
 
-zx_status_t zxio_vmofile_init(zxio_vmofile_t* file, zx_handle_t control,
+static_assert(sizeof(zxio_vmofile_t) <= sizeof(zxio_storage_t),
+              "zxio_vmofile_t must fit inside zxio_storage_t.");
+
+zx_status_t zxio_vmofile_init(zxio_storage_t* file, zx_handle_t control,
                               zx_handle_t vmo, zx_off_t offset, zx_off_t length,
                               zx_off_t seek);
 
@@ -68,7 +74,10 @@ typedef struct zxio_pipe {
     zx_handle_t socket;
 } zxio_pipe_t;
 
-zx_status_t zxio_pipe_init(zxio_pipe_t* pipe, zx_handle_t socket);
+static_assert(sizeof(zxio_pipe_t) <= sizeof(zxio_storage_t),
+              "zxio_vmofile_t must fit inside zxio_storage_t.");
+
+zx_status_t zxio_pipe_init(zxio_storage_t* pipe, zx_handle_t socket);
 
 __END_CDECLS
 
diff --git a/system/ulib/zxio/include/lib/zxio/ops.h b/system/ulib/zxio/include/lib/zxio/ops.h
index 6e42ce9e10bdb1606f884cf82c0736fb15b955d4..1dab9559326e5a67caff3e5dc05767916b57aec2 100644
--- a/system/ulib/zxio/include/lib/zxio/ops.h
+++ b/system/ulib/zxio/include/lib/zxio/ops.h
@@ -18,6 +18,17 @@ typedef struct zxio {
     uint64_t reserved[4];
 } zxio_t;
 
+// Storage for the |zxio_ops_t| implementation.
+typedef struct zxio_private {
+    uint64_t reserved[6];
+} zxio_private_t;
+
+// The storage backing a |zxio_t|.
+typedef struct zxio_storage {
+    zxio_t io;
+    zxio_private_t reserved;
+} zxio_storage_t;
+
 // A table of operations for a zxio_t.
 //
 // Most of the functions that operate on a zxio_t call through this operations
diff --git a/system/ulib/zxio/pipe.cpp b/system/ulib/zxio/pipe.cpp
index 82846409c02416b236781739c5e4c256055ca665..5513a9534a258db1dda21070addde61cc4aa78a9 100644
--- a/system/ulib/zxio/pipe.cpp
+++ b/system/ulib/zxio/pipe.cpp
@@ -113,7 +113,8 @@ static const zxio_ops_t zxio_pipe_ops = {
     .rewind = zxio_null_rewind,
 };
 
-zx_status_t zxio_pipe_init(zxio_pipe_t* pipe, zx_handle_t socket) {
+zx_status_t zxio_pipe_init(zxio_storage_t* storage, zx_handle_t socket) {
+    zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(storage);
     zxio_init(&pipe->io, &zxio_pipe_ops);
     pipe->socket = socket;
     return ZX_OK;
diff --git a/system/ulib/zxio/remote.cpp b/system/ulib/zxio/remote.cpp
index dfe0f3a16db3233c67c90f7379fc12d2b0faa37c..adffe8cc64c1ace117f5a90a201314e0d0aa5d67 100644
--- a/system/ulib/zxio/remote.cpp
+++ b/system/ulib/zxio/remote.cpp
@@ -379,10 +379,11 @@ static const zxio_ops_t zxio_remote_ops = {
     .rewind = zxio_remote_rewind,
 };
 
-zx_status_t zxio_remote_init(zxio_remote_t* rio, zx_handle_t control,
+zx_status_t zxio_remote_init(zxio_storage_t* storage, zx_handle_t control,
                              zx_handle_t event) {
-    zxio_init(&rio->io, &zxio_remote_ops);
-    rio->control = control;
-    rio->event = event;
+    zxio_remote_t* remote = reinterpret_cast<zxio_remote_t*>(storage);
+    zxio_init(&remote->io, &zxio_remote_ops);
+    remote->control = control;
+    remote->event = event;
     return ZX_OK;
 }
diff --git a/system/ulib/zxio/vmofile.cpp b/system/ulib/zxio/vmofile.cpp
index a7906c9faa69d41381a608a69b1a6db1a2781d8a..e4ef5023ca298773a256d271d9fa1f7dbff4349b 100644
--- a/system/ulib/zxio/vmofile.cpp
+++ b/system/ulib/zxio/vmofile.cpp
@@ -176,9 +176,10 @@ static const zxio_ops_t zxio_vmofile_ops = {
     .rewind = zxio_null_rewind,
 };
 
-zx_status_t zxio_vmofile_init(zxio_vmofile_t* file, zx_handle_t control,
+zx_status_t zxio_vmofile_init(zxio_storage_t* storage, zx_handle_t control,
                               zx_handle_t vmo, zx_off_t offset, zx_off_t length,
                               zx_off_t seek) {
+    zxio_vmofile_t* file = reinterpret_cast<zxio_vmofile_t*>(storage);
     zxio_init(&file->io, &zxio_vmofile_ops);
     if (seek > length)
         seek = length;
diff --git a/system/utest/zxio/vmofile-test.cpp b/system/utest/zxio/vmofile-test.cpp
index c81d2656c109d92784f10b513c52e30b2db20ea0..6b8f0648639fac2140df085cc43dfd22935ff761 100644
--- a/system/utest/zxio/vmofile-test.cpp
+++ b/system/utest/zxio/vmofile-test.cpp
@@ -19,9 +19,9 @@ bool vmofile_basic_test(void) {
     ASSERT_EQ(ZX_OK, backing.write(ALPHABET, 0, len));
     ASSERT_EQ(ZX_OK, backing.write(ALPHABET, len, len + len));
 
-    zxio_vmofile_t file;
-    zxio_vmofile_init(&file, ZX_HANDLE_INVALID, backing.release(), 4, len, 3);
-    zxio_t* io = &file.io;
+    zxio_storage_t storage;
+    zxio_vmofile_init(&storage, ZX_HANDLE_INVALID, backing.release(), 4, len, 3);
+    zxio_t* io = &storage.io;
 
     zxio_signals_t observed = ZXIO_SIGNAL_NONE;
     ASSERT_EQ(ZX_ERR_NOT_SUPPORTED, zxio_wait_one(io, ZXIO_READABLE,