diff --git a/quantum/quantum.h b/quantum/quantum.h
index cb0af306ac..59c3dd4904 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -53,6 +53,7 @@
 #include "eeconfig.h"
 #include "bootloader.h"
 #include "timer.h"
+#include "sync_timer.h"
 #include "config_common.h"
 #include "led.h"
 #include "action_util.h"
diff --git a/quantum/rgb_matrix.c b/quantum/rgb_matrix.c
index f239bd582f..a3dd51f7b3 100644
--- a/quantum/rgb_matrix.c
+++ b/quantum/rgb_matrix.c
@@ -266,9 +266,9 @@ static bool rgb_matrix_none(effect_params_t *params) {
 
 static void rgb_task_timers(void) {
 #if defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
-    uint32_t deltaTime = timer_elapsed32(rgb_timer_buffer);
+    uint32_t deltaTime = sync_timer_elapsed32(rgb_timer_buffer);
 #endif  // defined(RGB_MATRIX_KEYREACTIVE_ENABLED) || RGB_DISABLE_TIMEOUT > 0
-    rgb_timer_buffer = timer_read32();
+    rgb_timer_buffer = sync_timer_read32();
 
     // Update double buffer timers
 #if RGB_DISABLE_TIMEOUT > 0
@@ -296,7 +296,7 @@ static void rgb_task_timers(void) {
 
 static void rgb_task_sync(void) {
     // next task
-    if (timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
+    if (sync_timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
 }
 
 static void rgb_task_start(void) {
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index 7f9e330d37..65308572db 100644
--- a/quantum/rgblight.c
+++ b/quantum/rgblight.c
@@ -29,7 +29,7 @@
 #endif
 #include "wait.h"
 #include "progmem.h"
-#include "timer.h"
+#include "sync_timer.h"
 #include "rgblight.h"
 #include "color.h"
 #include "debug.h"
@@ -684,18 +684,16 @@ static void rgblight_layers_write(void) {
 
 #    ifdef RGBLIGHT_LAYER_BLINK
 rgblight_layer_mask_t _blinked_layer_mask = 0;
-uint16_t              _blink_duration     = 0;
 static uint16_t       _blink_timer;
 
 void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) {
     rgblight_set_layer_state(layer, true);
     _blinked_layer_mask |= 1 << layer;
-    _blink_timer    = timer_read();
-    _blink_duration = duration_ms;
+    _blink_timer = sync_timer_read() + duration_ms;
 }
 
 void rgblight_unblink_layers(void) {
-    if (_blinked_layer_mask != 0 && timer_elapsed(_blink_timer) > _blink_duration) {
+    if (_blinked_layer_mask != 0 && timer_expired(sync_timer_read(), _blink_timer)) {
         for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) {
             if ((_blinked_layer_mask & 1 << layer) != 0) {
                 rgblight_set_layer_state(layer, false);
@@ -799,7 +797,7 @@ void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) {
         animation_status.restart = true;
     }
 #        endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */
-#    endif     /* RGBLIGHT_USE_TIMER */
+#    endif /* RGBLIGHT_USE_TIMER */
 }
 #endif /* RGBLIGHT_SPLIT */
 
@@ -832,7 +830,7 @@ void rgblight_timer_enable(void) {
     if (!is_static_effect(rgblight_config.mode)) {
         rgblight_status.timer_enabled = true;
     }
-    animation_status.last_timer = timer_read();
+    animation_status.last_timer = sync_timer_read();
     RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
     dprintf("rgblight timer enabled.\n");
 }
@@ -941,18 +939,19 @@ void rgblight_task(void) {
 #    endif
         if (animation_status.restart) {
             animation_status.restart    = false;
-            animation_status.last_timer = timer_read() - interval_time - 1;
+            animation_status.last_timer = sync_timer_read();
             animation_status.pos16      = 0;  // restart signal to local each effect
         }
-        if (timer_elapsed(animation_status.last_timer) >= interval_time) {
+        uint16_t now = sync_timer_read();
+        if (timer_expired(now, animation_status.last_timer)) {
 #    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
             static uint16_t report_last_timer = 0;
             static bool     tick_flag         = false;
             uint16_t        oldpos16;
             if (tick_flag) {
                 tick_flag = false;
-                if (timer_elapsed(report_last_timer) >= 30000) {
-                    report_last_timer = timer_read();
+                if (timer_expired(now, report_last_timer)) {
+                    report_last_timer += 30000;
                     dprintf("rgblight animation tick report to slave\n");
                     RGBLIGHT_SPLIT_ANIMATION_TICK;
                 }
diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c
index 467ff81a97..6856b60558 100644
--- a/quantum/split_common/transport.c
+++ b/quantum/split_common/transport.c
@@ -6,6 +6,7 @@
 #include "quantum.h"
 
 #define ROWS_PER_HAND (MATRIX_ROWS / 2)
+#define SYNC_TIMER_OFFSET 2
 
 #ifdef RGBLIGHT_ENABLE
 #    include "rgblight.h"
@@ -27,6 +28,9 @@ static pin_t encoders_pad[] = ENCODERS_PAD_A;
 #    include "i2c_slave.h"
 
 typedef struct _I2C_slave_buffer_t {
+#    ifndef DISABLE_SYNC_TIMER
+    uint32_t sync_timer;
+#    endif
     matrix_row_t smatrix[ROWS_PER_HAND];
     uint8_t      backlight_level;
 #    if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
@@ -44,6 +48,7 @@ static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_re
 
 #    define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level)
 #    define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync)
+#    define I2C_SYNC_TIME_START offsetof(I2C_slave_buffer_t, sync_timer)
 #    define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, smatrix)
 #    define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state)
 #    define I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm)
@@ -91,10 +96,18 @@ bool transport_master(matrix_row_t matrix[]) {
         }
     }
 #    endif
+
+#    ifndef DISABLE_SYNC_TIMER
+    i2c_buffer->sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
+    i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_SYNC_TIME_START, (void *)&i2c_buffer->sync_timer, sizeof(i2c_buffer->sync_timer), TIMEOUT);
+#    endif
     return true;
 }
 
 void transport_slave(matrix_row_t matrix[]) {
+#    ifndef DISABLE_SYNC_TIMER
+    sync_timer_update(i2c_buffer->sync_timer);
+#    endif
     // Copy matrix to I2C buffer
     memcpy((void *)i2c_buffer->smatrix, (void *)matrix, sizeof(i2c_buffer->smatrix));
 
@@ -133,12 +146,15 @@ typedef struct _Serial_s2m_buffer_t {
     matrix_row_t smatrix[ROWS_PER_HAND];
 
 #    ifdef ENCODER_ENABLE
-    uint8_t      encoder_state[NUMBER_OF_ENCODERS];
+    uint8_t encoder_state[NUMBER_OF_ENCODERS];
 #    endif
 
 } Serial_s2m_buffer_t;
 
 typedef struct _Serial_m2s_buffer_t {
+#    ifndef DISABLE_SYNC_TIMER
+    uint32_t sync_timer;
+#    endif
 #    ifdef BACKLIGHT_ENABLE
     uint8_t backlight_level;
 #    endif
@@ -251,11 +267,19 @@ bool transport_master(matrix_row_t matrix[]) {
     // Write wpm to slave
     serial_m2s_buffer.current_wpm = get_current_wpm();
 #    endif
+
+#    ifndef DISABLE_SYNC_TIMER
+    serial_m2s_buffer.sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
+#    endif
     return true;
 }
 
 void transport_slave(matrix_row_t matrix[]) {
     transport_rgblight_slave();
+#    ifndef DISABLE_SYNC_TIMER
+    sync_timer_update(serial_m2s_buffer.sync_timer);
+#    endif
+
     // TODO: if MATRIX_COLS > 8 change to pack()
     for (int i = 0; i < ROWS_PER_HAND; ++i) {
         serial_s2m_buffer.smatrix[i] = matrix[i];
diff --git a/tmk_core/common.mk b/tmk_core/common.mk
index fdf2aa0972..05839824c0 100644
--- a/tmk_core/common.mk
+++ b/tmk_core/common.mk
@@ -18,6 +18,7 @@ TMK_COMMON_SRC +=	$(COMMON_DIR)/host.c \
 	$(COMMON_DIR)/report.c \
 	$(PLATFORM_COMMON_DIR)/suspend.c \
 	$(PLATFORM_COMMON_DIR)/timer.c \
+	$(COMMON_DIR)/sync_timer.c \
 	$(PLATFORM_COMMON_DIR)/bootloader.c \
 
 ifeq ($(PLATFORM),AVR)
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c
index 8c7bdc8b55..a1fbc01da6 100644
--- a/tmk_core/common/keyboard.c
+++ b/tmk_core/common/keyboard.c
@@ -23,6 +23,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "led.h"
 #include "keycode.h"
 #include "timer.h"
+#include "sync_timer.h"
 #include "print.h"
 #include "debug.h"
 #include "command.h"
@@ -255,6 +256,7 @@ __attribute__((weak)) void housekeeping_task_user(void) {}
  */
 void keyboard_init(void) {
     timer_init();
+    sync_timer_init();
     matrix_init();
 #ifdef VIA_ENABLE
     via_init();
diff --git a/tmk_core/common/sync_timer.c b/tmk_core/common/sync_timer.c
new file mode 100644
index 0000000000..de24b463b6
--- /dev/null
+++ b/tmk_core/common/sync_timer.c
@@ -0,0 +1,58 @@
+/*
+Copyright (C) 2020 Ryan Caltabiano <https://github.com/XScorpion2>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+If you happen to meet one of the copyright holders in a bar you are obligated
+to buy them one pint of beer.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include "sync_timer.h"
+#include "keyboard.h"
+
+#if defined(SPLIT_KEYBOARD) && !defined(DISABLE_SYNC_TIMER)
+volatile int32_t sync_timer_ms;
+
+void sync_timer_init(void) { sync_timer_ms = 0; }
+
+void sync_timer_update(uint32_t time) {
+    if (is_keyboard_master()) return;
+    sync_timer_ms = time - timer_read32();
+}
+
+uint16_t sync_timer_read(void) {
+    if (is_keyboard_master()) return timer_read();
+    return sync_timer_read32();
+}
+
+uint32_t sync_timer_read32(void) {
+    if (is_keyboard_master()) return timer_read32();
+    return sync_timer_ms + timer_read32();
+}
+
+uint16_t sync_timer_elapsed(uint16_t last) {
+    if (is_keyboard_master()) return timer_elapsed(last);
+    return TIMER_DIFF_16(sync_timer_read(), last);
+}
+
+uint32_t sync_timer_elapsed32(uint32_t last) {
+    if (is_keyboard_master()) return timer_elapsed32(last);
+    return TIMER_DIFF_32(sync_timer_read32(), last);
+}
+#endif
diff --git a/tmk_core/common/sync_timer.h b/tmk_core/common/sync_timer.h
new file mode 100644
index 0000000000..9ddef45bb2
--- /dev/null
+++ b/tmk_core/common/sync_timer.h
@@ -0,0 +1,54 @@
+/*
+Copyright (C) 2020 Ryan Caltabiano <https://github.com/XScorpion2>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+If you happen to meet one of the copyright holders in a bar you are obligated
+to buy them one pint of beer.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#pragma once
+
+#include <stdint.h>
+#include "timer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(SPLIT_KEYBOARD) && !defined(DISABLE_SYNC_TIMER)
+void     sync_timer_init(void);
+void     sync_timer_update(uint32_t time);
+uint16_t sync_timer_read(void);
+uint32_t sync_timer_read32(void);
+uint16_t sync_timer_elapsed(uint16_t last);
+uint32_t sync_timer_elapsed32(uint32_t last);
+#else
+#    define sync_timer_init()
+#    define sync_timer_clear()
+#    define sync_timer_update(t)
+#    define sync_timer_read() timer_read()
+#    define sync_timer_read32() timer_read32()
+#    define sync_timer_elapsed(t) timer_elapsed(t)
+#    define sync_timer_elapsed32(t) timer_elapsed32(t)
+#endif
+
+#ifdef __cplusplus
+}
+#endif