diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 65381fcce7deab44da51c47e5932f64f92abcfef..c3847908cec9291db512e87e390a7e543ef88bb3 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -1524,9 +1524,10 @@
   // Default number of triangles
   #define NOZZLE_CLEAN_TRIANGLES  3
 
-  // Specify positions as { X, Y, Z }
-  #define NOZZLE_CLEAN_START_POINT {  30, 30, (Z_MIN_POS + 1) }
-  #define NOZZLE_CLEAN_END_POINT   { 100, 60, (Z_MIN_POS + 1) }
+  // Specify positions for each tool as { { X, Y, Z }, { X, Y, Z } }
+  // Dual hotend system may use { {  -20, (Y_BED_SIZE / 2), (Z_MIN_POS + 1) },  {  420, (Y_BED_SIZE / 2), (Z_MIN_POS + 1) }}
+  #define NOZZLE_CLEAN_START_POINT { {  30, 30, (Z_MIN_POS + 1) } }
+  #define NOZZLE_CLEAN_END_POINT   { { 100, 60, (Z_MIN_POS + 1) } }
 
   // Circular pattern radius
   #define NOZZLE_CLEAN_CIRCLE_RADIUS 6.5
diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index e76e536a96b3b33d561bc44da7b94dc7ea79ce1b..081d4f96db3b7fac693aa1b1b028c4185f519f9a 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -1771,6 +1771,9 @@
   // Z raise distance for tool-change, as needed for some extruders
   #define TOOLCHANGE_ZRAISE     2  // (mm)
   //#define TOOLCHANGE_NO_RETURN   // Never return to the previous position on tool-change
+  #if ENABLED(TOOLCHANGE_NO_RETURN)
+    //#define EVENT_GCODE_AFTER_TOOLCHANGE "G12X"   // G-code to run after tool-change is complete
+  #endif
 
   // Retract and prime filament on tool-change
   //#define TOOLCHANGE_FILAMENT_SWAP
diff --git a/Marlin/src/libs/nozzle.cpp b/Marlin/src/libs/nozzle.cpp
index acacbe3392518bf19890584a0d5c167bc879f212..f9b09c2fa9cf1bdf33b13709777c6bef75abd19d 100644
--- a/Marlin/src/libs/nozzle.cpp
+++ b/Marlin/src/libs/nozzle.cpp
@@ -157,26 +157,24 @@ Nozzle nozzle;
    * @param argument depends on the cleaning pattern
    */
   void Nozzle::clean(const uint8_t &pattern, const uint8_t &strokes, const float &radius, const uint8_t &objects, const uint8_t cleans) {
-    xyz_pos_t start = NOZZLE_CLEAN_START_POINT, end = NOZZLE_CLEAN_END_POINT;
+    xyz_pos_t start[HOTENDS] = NOZZLE_CLEAN_START_POINT, end[HOTENDS] = NOZZLE_CLEAN_END_POINT, middle[HOTENDS] = NOZZLE_CLEAN_CIRCLE_MIDDLE;
 
     if (pattern == 2) {
       if (!(cleans & (_BV(X_AXIS) | _BV(Y_AXIS)))) {
         SERIAL_ECHOLNPGM("Warning : Clean Circle requires XY");
         return;
       }
-      constexpr xyz_pos_t middle NOZZLE_CLEAN_CIRCLE_MIDDLE;
-      end = middle;
     }
     else {
-      if (!TEST(cleans, X_AXIS)) start.x = end.x = current_position.x;
-      if (!TEST(cleans, Y_AXIS)) start.y = end.y = current_position.y;
+      if (!TEST(cleans, X_AXIS)) start[active_extruder].x = end[active_extruder].x = current_position.x;
+      if (!TEST(cleans, Y_AXIS)) start[active_extruder].y = end[active_extruder].y = current_position.y;
     }
-    if (!TEST(cleans, Z_AXIS)) start.z = end.z = current_position.z;
+    if (!TEST(cleans, Z_AXIS)) start[active_extruder].z = end[active_extruder].z = current_position.z;
 
     switch (pattern) {
-       case 1: zigzag(start, end, strokes, objects); break;
-       case 2: circle(start, end, strokes, radius);  break;
-      default: stroke(start, end, strokes);
+       case 1: zigzag(start[active_extruder], end[active_extruder], strokes, objects); break;
+       case 2: circle(start[active_extruder], middle[active_extruder], strokes, radius);  break;
+      default: stroke(start[active_extruder], end[active_extruder], strokes);
     }
   }
 
diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp
index 021da6f3d4598ce6fc14af375bd98f7a72d5451c..45c5805f4daf74670480371cae151546f60d3d17 100644
--- a/Marlin/src/module/tool_change.cpp
+++ b/Marlin/src/module/tool_change.cpp
@@ -1067,6 +1067,10 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
       fanmux_switch(active_extruder);
     #endif
 
+    #ifdef EVENT_GCODE_AFTER_TOOLCHANGE
+      gcode.process_subcommands_now_P(EVENT_GCODE_AFTER_TOOLCHANGE);
+    #endif
+
     SERIAL_ECHO_START();
     SERIAL_ECHOLNPAIR(MSG_ACTIVE_EXTRUDER, int(active_extruder));