The best I have is manual RHS holding and Join, after which an arbitrary head could be Applied:
Join @@ Cases[expr, x : _Times :> Hold[x], 3] Hold[2/2, 8/4, 1/0]
This could be done automatically as follows:
makeHeld[(L_ -> R_) | (L_ :> R_)] := L :> HoldComplete[R]; makeHeld[pat_] := x : pat :> HoldComplete[x]; heldCases[expr_, rule_, args___] := Join @@ Cases[expr, makeHeld @ rule, args] I wonder if there is a more elegant or efficient method.
(Edit: I made the inner replacement a separate function because it is slightly more efficient and easier to read.)