To access the next element, map on tails instead:
mapWithNext op xs = map g (tails xs)
  where
  g (x:y:_) = Just (op x y)
  g _       = Nothing
since when there's no next element, your op can't be applied, though it will only happen with the finite lists. You might know that the input lists will be infinite, but your type doesn't, so it's better to be on the safe side.
You might want to add a post-processing step to get rid of the final Nothing(s) and extract the Just values. catMaybes :: [Maybe a] -> [a] seems applicable.
Of course using zipWith(*) mentioned in the comments is cleaner and more to the point, here; but this way with tails is more versatile in general, i.e. it is easier to amend to be used with e.g. ternary op, etc.. With zipWith we'd have to use a chain of nested zipWith applications and build artificial tuples just to have access to the elements; with tails we don't need to do anything like that at all.
A combination of map (generally, foldr) with tails is actually emulating paramorphism. It has its merits so as e.g. in Common Lisp it is actually present as a library function maplist.
(*) you could say, zipWith is not map, but   e.g. in Scheme it is so. There, map accepts an arbitrary number of argument lists, and a combining operation of the corresponding arity. But of course Haskell is not Scheme.